- Создание дружественных к пользователю XML-интерфейсов с помощью Windows PowerShell
- Механизм разбора XML
- Создание приложения Windows Forms
- Клёвый код
- Решаем задачи Абрамян на C. Matrix78
- Решаем задачи Абрамян на C. Matrix77
- Решаем задачи Абрамян на C. Matrix76
- Решаем задачи Абрамян на C. Matrix75
- Решаем задачи Абрамян на C. Matrix74
- Решаем задачи Абрамян на C. Matrix73
- Решаем задачи Абрамян на C. Matrix72
- Решаем задачи Абрамян на C. Matrix71
- Решаем задачи Абрамян на C. Matrix70
- Решаем задачи Абрамян на C. Matrix69
- WPF формы для PowerShell скриптов
Создание дружественных к пользователю XML-интерфейсов с помощью Windows PowerShell
Продукты и технологии:
Windows PowerShell, Windows Forms, XML, XPath
В статье рассматриваются:
- создание механизма разбора XML;
- конструирование Windows Forms;
- поиск или редактирование XML-файлов с использованием XPath-запросов.
Скриптовый язык Windows PowerShell делает все, что можно пожелать для инструмента командной строки, и даже настолько больше, что в конечном счете он мог бы заменить такие технологии, как VBScript. Хорошее общее описание того, что такое Windows PowerShell, и основы его применения см. по ссылкам bit.ly/LE4SU6 и bit.ly/eBucBI.
Windows PowerShell полностью интегрирован с Microsoft .NET Framework, а значит, глубоко связан с XML — текущим международным стандартом для обмена данными с использованием структурированных текстовых файлов. Общую информацию о XML см. по ссылке bit.ly/JHfzw.
В этой статье исследуются возможности Windows PowerShell в представлении XML-данных и манипуляций над ними с целью создания относительно простого UI для чтения и редактирования XML-файлов. Идея в том, чтобы упростить и сделать это более удобным, используя алгоритмы, «понимающие» отношения одного уровня и предок-потомок в любом конкретном файле, даже ничего не зная о его схеме. Я также рассмотрю применение Windows Forms в Windows PowerShell, запросы XPath и другие релевантные технологии. Предлагаемое мной приложение может обрабатывать XML-файл и генерировать XPath-запросы.
Давайте обсудим, как анализировать любой XML-файл в Windows PowerShell и представить его в формате, которым смогут пользоваться люди без глубоких технических познаний. На рис. 1 показан предварительный набросок того типа GUI, который вы можете создать.
Рис. 1. Предварительный набросок GUI
Ключом к тому, чтобы добиться всего этого, является введение в приложение Windows PowerShell поддержки разбора и понимания любого XML-файла без знания его схемы или вмешательства человека. После исследования существующих технологий автоматизированного анализа XML-файлов я решил разработать свой механизм синтаксического анализа (разбора) для этой специфической цели, так как мне не удалось найти ничего, что полностью удовлетворяло бы моим требованиям (программа должна понимать XML-документы без участия человека). В настоящее время приложения, как правило, предполагают, что разработчик или пользователь хорошо знаком с элементами, атрибутами и общей схемой любого конкретного XML-документа. Но на практике в ряде ситуаций (возможно, даже во многих) это вовсе не так. Например, такая парадигма ведет к провалу в сценарии, где множество потребителей данных, не являющихся экспертами в области XML, вынуждены обращаться к самым разнообразным источникам XML-данных. Аналогично даже при наличии одного-двух экспертов, если организации приходится иметь дело с сотнями или тысячами XML-файлов с разной структурой, их обработка людьми может стать неэффективной.
Таким образом, нужен механизм разбора, способный читать любой XML-файл и генерировать XPath-запросы для поиска и редактирования XML-файлов, которые могли бы применять обычные пользователи с минимальным уровнем познаний в этой области.
Механизм разбора XML
Для совместимости с XML в любом документе открывающие и закрывающие скобки должны быть парными друг другу.
Первым делом подготовим набор массивов для хранения всех открывающих и закрывающих скобок в XML-файле:
Чтобы создать в Windows PowerShell строго типизированный массив неизвестного размера, нужны три элемента: [type[]], $name и символ массива неизвестного размера — @(). Переменные в Windows PowerShell принимают $ как символ, с которого они начинаются. Конкретно эти массивы охватывают индексируемые адреса открывающих и закрывающих угловых скобок в XML-документе, а также строковые значения имен элементов, сопоставленных с этими скобками. Например, для строки
в XML целочисленный индекс открывающих скобок был бы равен 0, а индекс закрывающих — 15. Открывающим и закрывающим значениями в этом случае был бы один и тот же PS1.
Чтобы получить наш целевой XML в память, используем следующий код:
На рис. 2 дан фрагмент используемого XML-файла.
Рис. 2. Фрагмент примера XML-файла
После операции загрузки эти XML-данные находятся в памяти. Чтобы проанализировать этот XML и манипулировать им, я использую объектную модель документа (document object model, DOM), экземпляр которой теперь создается в переменной $xdoc (но мне также понадобится задействовать технологию XPathNavigator для некоторых специфических целей, о которых я расскажу немного позже):
Одно из наиболее интересных средств Windows PowerShell — встроенная функция, или командлет (cmdlet), называемый Get-Member; он позволяет просматривать методы и свойства любого объекта в Windows PowerShell прямо в IDE в процессе разработки. На рис. 3 показаны результаты вызова этого командлета применительно к только что созданному объекту $nav, а на рис. 4 — результаты, отображаемые в Windows PowerShell Integrated Scripting Environment (ISE) после вызова Get-Help.
Рис. 3. Результаты вызова Get-Member
Рис. 4. Результаты вызова Get-Help в Windows PowerShell
While Get-Member will often put you on the right track during Windows PowerShell development, you’ll also find the associated Get-Help cmdlet handy during this process.
If you type get-help xml at the command line, as shown in Figure 4, you’ll get the output shown here:
Если вы введете get-help about_types.ps1xml, то получите результаты, как на рис. 5..
Рис. 5. Получение справки о файлах Types.ps1xml
Интегрированная система Windows PowerShell обеспечивает всестороннее исследование синтаксиса и сравнительно проста в использовании. Эта тема вообще заслуживает отдельной статьи.
Чтобы привести XML к состоянию, готовому для анализа, используйте метод Select объекта XpathNavigator:
В первой части этого выражения я вызываю .Select в простом XPath-запросе «/», предоставляя весь XML-контент. Во второй части, после символа «|», обозначающего в Windows PowerShell объектный конвейер, я выполняю foreach, представленный псевдонимом %; вместо этого псевдонима я мог бы использовать foreach. В цикле я формирую строковые XML-данные в переменной $ouxml из свойства .OuterXML для объектов, обрабатываемых в этом цикле. Вернувшись к рис. 3, вы увидите, что .OuterXML является одним из свойств объекта XPathNavigator. Это свойство предоставляет полный набор всех угловых скобок в XML-файле, необходимых для корректной работы механизма разбора.
Заметьте, что для объектов, проходящих конвейер, $_ является символом конкретного экземпляра, а нотация с точкой используется для получения свойств и методов каждого экземпляра. Адресация или ссылка на каждый объект в конвейере осуществляется с помощью символа $_. Чтобы получить атрибут объекта $_, напишите, например, $_.Name (еслиName — свойство-член конкретного объекта). Все, что передается через конвейер Windows PowerShell, является объектом со свойствами и методами.
Последняя фаза подготовки к разбору — «регуляризация» («regularize») XML-текста с обработкой любых особых случаев, которые выглядят как . Механизм разбора увидит ту же информацию в другом формате: . Следующий код начинает это преобразование, используя RegEx и отыскивая совпадения:
Теперь вы можете посмотреть на основной аналитический код для этого приложения: механизм разбора, который заполнит перечисленные ранее четыре массива. Код, проверяющий файл на открывающие скобки, показан на рис. 6.
Рис. 6. Проверка файла на наличие открывающих скобок
Код на рис. 6 обрабатывает особый случай с корневым элементом XML-документа. Еще одно фундаментальное правило XML заключается в том, что каждая схема должна содержать один общий корневой набор (overall root set) угловых скобок; внутри этих замыкающих символов XML-данные можно структурировать как угодно, лишь бы это отвечало ранее упомянутому правилу парности, т. е. для каждого должен быть :
Как только вы нашли конечную точку, используйте $indx_to_use, чтобы было проще выделить строку, сопоставленную с открывающей угловой скобкой, которая сейчас находится в фокусе:
По сути, открывающее значение (leading value) — это строка, начинающаяся с .
Теперь можно извлечь парные закрывающие угловые скобки поиском строки > в Windows PowerShell.
Создание приложения Windows Forms
Поскольку Windows PowerShell является хостом для .NET-библиотек и классов, вы можете писать следующий код и тем самым сделать доступными для своего приложения Windows Forms и .NET-классы Drawing:
Теперь вы можете создать форму и разместить на ней элементы управления:
Стоит отметить, что add_Click — это способ подключения события к элементу управления в Windows PowerShell. В данном случае к событию щелчка кнопки подключается вызов функции. Код на рис. 8 добавляет кнопки и текстовые поля.
Рис. 8. Добавление кнопок и текстовых полей
Чтобы заполнить $listbox вашим набором XPath-запросов, сделайте так:
На рис. 9 показан UI со сгенерированными XPath-запросами; при этом один из запросов выбран пользователем.
Рис. 9. Выбор XPath-запроса
На финальном этапе пользователь нажимает кнопку GetXMLData и получает результаты, приведенные на рис. 10.
Рис. 10. Окно результатов
Вот и все — вы получили простой UI для чтения и редактирования XML-файлов, созданный исключительно средствами Windows PowerShell. В последующих онлайновых статьях я продолжу эту тему и расскажу, как обрабатывать XML-файлы, использующие пространства имен, а также продемонстрирую применение показанных здесь методик для поддержки редактирования XML-файлов через этот интерфейс.
Джо Лейбовиц (Joe Leibowitz) — консультант, специализирующийся на инфраструктурных проектах. С ним можно связаться по адресу joe.leibowitz@bridgewaresolutions.com.
Выражаю благодарность за рецензирование статьи эксперту Томасу Петчелу (Thomas Petchel).
Клёвый код
Скриптописание и кодинг
Решаем задачи Абрамян на C. Matrix78
Matrix78. Дана матрица размера $$M \times N$$. Упорядочить ее строки так, чтобы их минимальные элементы образовывали убывающую последовательность.
Решаем задачи Абрамян на C. Matrix77
Matrix77. Дана матрица размера $$M \times N$$. Упорядочить ее столбцы так, чтобы их последние элементы образовывали убывающую последовательность.
Решаем задачи Абрамян на C. Matrix76
Matrix76. Дана матрица размера $$M \times N$$. Упорядочить ее строки так, чтобы их первые элементы образовывали возрастающую последовательность.
Решаем задачи Абрамян на C. Matrix75
Matrix75. Дана матрица размера $$M \times N$$. Элемент матрицы называется ее локальным максимумом, если он больше всех окружающих его элементов. Поменять знак всех локальных максимумов данной матрицы на противоположный. При решении допускается использовать вспомогательную матрицу.
Решаем задачи Абрамян на C. Matrix74
Matrix74. Дана матрица размера $$M \times N$$. Элемент матрицы называется ее локальным минимумом, если он меньше всех окружающих его элементов. Заменить все локальные минимумы данной матрицы на нули. При решении допускается использовать вспомогательную матрицу.
Решаем задачи Абрамян на C. Matrix73
Matrix73. Дана матрица размера $$M \times N$$. После последнего столбца, содержащего только отрицательные элементы, вставить столбец из нулей. Если требуемых столбцов нет, то вывести матрицу без изменений.
Решаем задачи Абрамян на C. Matrix72
Matrix72. Дана матрица размера $$M \times N$$. Перед первым столбцом, содержащим только положительные элементы, вставить столбец из единиц. Если требуемых столбцов нет, то вывести матрицу без изменений.
Решаем задачи Абрамян на C. Matrix71
Matrix71. Дана матрица размера $$M \times N$$. Продублировать столбец матрицы, содержащий ее минимальный элемент.
Решаем задачи Абрамян на C. Matrix70
Matrix70. Дана матрица размера $$M \times N$$. Продублировать строку матрицы, содержащую ее максимальный элемент.
Решаем задачи Абрамян на C. Matrix69
Matrix69. Дана матрица размера $$M \times N$$ и целое число $$K$$ $$(1 \le K \le $$N$$)$$. После столбца матрицы с номером $$K$$ вставить столбец из единиц.
WPF формы для PowerShell скриптов
Иногда, при написании PowerShell скриптов, появляется необходимость отобразить некую форму для ввода каких-нибудь параметров или наоборот для отображения результатов скрипта. Ранее для этого я использовал Windows Forms, но у этого метода есть очевидные недостатки – при создании формы необходимо описывать в коде скрипта каждый элемент формы и его свойства. Недавно натолкнулся на несколько статей от “ Hey, Scripting Guy ”, по использованию форм WPF в скриптах PowerShell. В одной из них описывается способ использования форм WPF, реализованный Крисом Конте. Суть его сводится к использованию отдельного скрипта-загрузчика формы и отдельного файла с xaml-описанием формы. В данной статье я хочу показать как легко создавать и использовать формы WPF в своих скриптах.
Необходимые инструменты
Для создания скриптов с формами WPF нам понадобится:
Создаем форму
Для создания формы очень удобно пользоваться Visual Studio Express 2013/2014 for Windows Desktop. Создаем новый проект Visual C# –> Windows –> WPF Application и рисуем там форму с необходимыми нам контролами. Я создал для примера такую:
Изменения, которые я внес:
- У самой формы я изменил заголовок (свойство Title) и размеры (свойства Height и Width)
- На форму поместил Label в свойство Content которой поместил текст “Это форма запущенная из под Powershell”, а так же изменил размер текста на 24pt
- Кнопка Button с текстом “Change” в свойстве Content
- Кнопка Button с текстом “Exit” в свойстве Content
В итоге мы получаем XAML текст с нашей формой
Это практически готовый XAML для использования его в нашем скрипте, единственное что нужно сделать – это удалить x:Class=“test.MainWindow” и сохранить его отдельном файле с расширением .xaml (например MyForm.xaml).
Загрузка формы
Для того что бы загрузить нашу форму Крис написал отличный скрипт который я публикую ниже.
Скрипт принимает в качестве параметра $XamlPath путь к файлу XAML. Помещает его содержимое в глобальную переменную $xmlWPF. В блоке try-catch призводится попытка загрузить сборки WPF и в случае ошибки сообщается о невозможности загрузить данные сборки. После чего в глобальную переменную $xamGUI загружается форма из переменной $xmlWPF c помощью сборки Windows.Markup.XamlReader. О последнем блоке ($xmlWPF.SelectNodes…) я расскажу чуть позже. Сохраним данный скрипт под именем loadForm.ps1 и поместим вместе с файлом MyForm.xaml.
Использование скрипта загрузки формы
Теперь нам осталось только воспользоваться плодами нашей работы. Создаем в Windows Powershell ISE (или другой IDE разработки, например PowerGUI) новый скрипт powershell и помещаем его в ту же папку, где и предыдущие файлы. Назовем его к примеру Main.ps1. Воспользуемся скриптом Криса что бы загрузить нашу форму:
Теперь если мы запустим это скрипт то увидим что наша форма появилась на экране.
Программирование событий формы
Мы смогли запустить нашу форму, однако пока что толку он нее очень мало, так как она мало функциональна. Нам нужна возможность определять события элементов формы (нажатие кнопок, и т.д.). Однако что бы как то обратиться к элементам формы нам нужны переменные со ссылками на объекты. Тут то нам и пригодится последний блок скрипта loadForm.ps1:
Этот блок делает обход всего дерева xaml и при нахождении аргументов типа Name создает переменные со ссылками на объекты (контролы) нашей формы.
Следовательно нам при создании формы нужно указывать имена (свойство Name) тех контролов, с которыми мы хотим в дальнейшем так или иначе взаимодействовать. Откроем файл нашей формы в текстовом редакторе, ISE или Visual Studio и добавим контролам имена, я дал например такие:
Самой форме при этом давать имя не нужно, мы можем обращаться к форме через глобальную переменную $xamGUI.
Сохранив наш новый код XAML в файл MyForm.xaml мы можем перезапустить наш скрипт Main.ps1, после чего увидим, что скрипт loadForm.ps1 создал переменные $btnChange, $btnExit.
Обратите внимание на тип переменной $btnChange – это [Button], так что это действительно ссылки на объекты формы. Теперь мы можем добавить код для событий наших контролов. Например для того что бы корректно работала кнопка Exit, мы должны закрывать форму при нажатии на кнопку. Это достигается через добавление кода для события Click:
Ну а что бы кнопка $btnChange меняла текст контрола Label1 добавим и ей код для события Click:
Теперь запустив наш скрипт мы можем убедиться в том, что наши кнопки теперь работают.
Собственно это все на сегодня. Если будет интерес к этой теме – буду рад написать еще несколько статей.