среда, 22 июня 2011 г.

Использование C# кода и объектов расширения (extension objects) в XSLT-процессоре .NET Framework

В .NET реализована спецификация XSLT 1.0 и его возможностей за частую не хватает. Например, отсутствует использование регулярных выражений, нет кодирования строк для использования в URL и т. д. В то же время .NET Framework позволяет обойти ограничения за счет таких средств как:
  1. параметры XSL трансформации;
  2. встраивание кода на JavaScript, VB.NET, C# и других языках;
  3. использование объектов расширения (extension objects.

В этой статье я хочу остановиться только на 2-х способах, которые сам регулярно использую, внедрение кода на С# и объекты расширения. Чтобы примеры были более конкретными, допустим, что у нас есть XML файл в котором содержатся данные для формирования линки на поиск в Bing. Вот пример такого XML файла:

Чтобы примеры были более конкретными, допустим, что у нас есть XML файл в котором содержатся данные для формирования линки на поиск в Bing.

Вот пример такого XML файла:

    xml version="1.0" encoding="utf-8" ?>

    <queries>

    <query title="A & B" term="A & B"/>

    queries>

Если в такого рода задаче не кодировать параметры для URL, то специальные символы (как &) не будут закодированы и URL будет распознан не верно либо может сформироваться невалидный URL.
Ниже приведен пример поиска по запросу из XML файла без кодирования параметров

    clip_image002

А здесь правильный вариант

    clip_image004

В первом случае символ & не был закодирован и не распознан, как часть строки поиска. Во втором случае & был закодирован и Bing распознал его.

Ниже приведены примеры, как можно добавить кодировние URL внедрением C# кода и с использованием объектов расширения. Фрагменты C# кода и XSLT на которые надо обратить внимание, выделены жирным и увеличенным шрифтом.

Пример XSLT с внедрением С# кода

    xml version="1.0" encoding="utf-8"?>

    <xsl:stylesheet

    version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:msxsl="urn:schemas-microsoft-com:xslt"

    xmlns:utility="urn:utility-scripts"

    exclude-result-prefixes="msxsl">

    <xsl:output method="html" indent="yes"/>

    <xsl:template match="query">

    <xsl:element name="a">

    <xsl:attribute name="href">

    <xsl:value-of select="concat('http://bing.com/search?q=', utility:EncodeUrl(@term))"/>

    xsl:attribute>

    <xsl:value-of select="@title"/>

    xsl:element>

    <br />

    xsl:template>

    <msxsl:script language="C#" implements-prefix="utility">

    <msxsl:assembly name="system.web" />

    public string EncodeUrl(string rawUrl) {

    return System.Web.HttpUtility.UrlEncode(rawUrl);

    }

    ]]>

    msxsl:script>

    xsl:stylesheet>

Пример с использованием объектов расширения
XSLT:

    xml version="1.0" encoding="utf-8"?>

    <xsl:stylesheet

    version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:msxsl="urn:schemas-microsoft-com:xslt"

    xmlns:utility="urn:utility-scripts"

    exclude-result-prefixes="msxsl">

    <xsl:output method="html" indent="yes"/>

    <xsl:template match="query">

    <xsl:element name="a">

    <xsl:attribute name="href">

    <xsl:value-of select="concat('http://bing.com/search?q=', utility:EncodeUrl(@term))"/>

    xsl:attribute>

    <xsl:value-of select="@title"/>

    xsl:element>

    <br />

    xsl:template>

    xsl:stylesheet>

Вызывающий C# код:

    class Program

    {

    static void Main(string[] args)

    {

    XslCompiledTransform xsltAndExtObjTransform = new XslCompiledTransform();

    xsltAndExtObjTransform.Load("..\\..\\XsltAndExtObj.xslt");

    XsltArgumentList arguments = new XsltArgumentList();

    arguments.AddExtensionObject("urn:utility-scripts", new Program());

    using (StreamWriter writer = File.CreateText("XsltAndExtObj.html"))

    {

    xsltAndExtObjTransform.Transform("..\\..\\Data.xml", arguments, writer);

    }

    }

    public string EncodeUrl(string rawUrl)

    {

    return System.Web.HttpUtility.UrlEncode(rawUrl);

    }

    }


Заключение
Описанные методы дают огромные возможности для расширения возможностей XSLT, но нужно помнить, что есть и плата – это потеря некоторой переносимости кода. Такой XSLT не возможно без переработки использовать в среде отличной от .NET – таких как Java или PHP и т. д.

Если же сравнивать межу собой внедрение c# кода и объекты расширения, то предпочтительней использовать объекты расширения. Их проще разрабатывать – есть подсветка синтаксиса и синтаксические ошибки выявляются на этапе компиляции проекта . Проще сопровождать – можно (и нужно) написать unit-test для проверки логических ошибок. Ну и на конец объект расширения можно будет использовать повторно (и не только в XSLT).

Удобство в использовании объектов расширения в том, что весь код, необходимый для их работы находится в том же XSLT файле. Без каких либо дополнительных усилий и зависимостей, XSLT c объектами расширения можно использовать в другой трансформации, другом .NET проекте.

В завершение статьи, тем кого заинтересовала данная тема хочу посоветовать посмотреть соответствующий раздел MSDN, где достаточно подробно описаны возможности расширения XSLT.

вторник, 7 июня 2011 г.

Эрик Гамма переходит на работу в Майкрософт

Как пишет в своем блоге Janson Zanders, признанный эксперт в области разработки программного обеспечения, соавтор книги Design Patterns, один из разработчиков JUnit и Eclipse -- Эрик Гамма присоединится к команде разработчиков Visual Studio и возглавит Visual Studio development lab в Цюрихе. Подробнее здесь.

понедельник, 6 июня 2011 г.

Незаменимых нет? (или чем заменить .NET Reflector)

Многие знают, что с июня месяца рефлектор стал платным. За неделю до этого события я решил подыскать себе бесплатную альтернативу. Выбирал среди ILSpy, JetBrains dotPeek и Telerik JustDecompile. Около недели я ими пользовался, и свои наблюдения я фиксировал в файлике. Таким образом, у меня появилась небольшая статья, которая, возможно, кому-нибудь облегчит выбор.

С основной задачей – декомпиляцией кода все приложения справляются достаточно хорошо. Поэтому следующим шагом стал выбор наиболее удобной в использовании замены рефлектора и развитость «второстепенного» функционала.

Наиболее важные для меня критерий выбора декомпилятора были следующие:

  1. Удобство работы
  2. Скорость работы (загрузка, поиск типа, декомпиляция)
  3. Функционал
    1. Analyze
    2. Декомпиляция в Visual Basic
    3. Search MSDN
    4. Поиск типа, метода, строки.

Естественно, поскольку, удобство работы, это очень нечеткий критерий, то и вывод мой, что мой вывод будет субъективным.

По скорости работы особых нареканий у меня тоже не оказалось. Точнее все работают приблизительно одинаково медленно ;), разве что Telerik JustDecompile грузится немого медленей других.

А вот по развитости второстепенного функционала продукты отличаются довольно сильно.

К сожалению, на текущий момент ни один из декомпиляторов не поддерживают следующие операции:

  • Поиск строки
  • Поиск выбранного типа в MSDN
  • Поиск выбранного типа в Bing

Однако, что поскольку разработка этих продуктов началась сравнительно недавно (февраль 2011) и еще идет полным ходом, функционал может существенно измениться. Поэтому ниже я привожу версии продуктов, между которыми я выбирал.

Далее я приведу скриншоты декомпиляторово и их краткое описание (отличие).


ILSpy билд 1.0.0.822

image

Очень похож на.NET Reflector. Умеет декомпилировать в C# и IL. Есть приятная функция, которой нет в рефлекторе и в других декомпиляторах – при декомпиляции кода показывает комментарии, что очень удобно.

Единственный из продуктов, который позволяет пометить сразу несколько сборок для удаления.

Telerik JustDecompile Beta билд 2011.1.516.2

image

Минусы начинаются со скачивания инсталлятора – при скачивании требует регистрации. У меня регистрация была, но в противном случае я бы его не стал скачивать.

Интересное совпадение, пока я писал эту статью JustDecompile показал мне уведомление, что есть обновленние, но что бы его скачать надо было опять вводить регистрационные данные. Лень мне стало их искать и обновление не стал скачивать.
Переборщили они с этим.

Немного не типичный интерфейс пользователя из-за чего создается впечатление что у программы Из рассматриваемых продуктов единственный, который на текущий момент умеет декомпилировать в C# и Visual Basic .NET.

Функция Analyze здесь называется Find Usages. Есть проблемы с поиском типов. Почему-то не всегда находит типы, так же не всегда при поиске типов фокус ввода в поле ввода. Мелочь, а неприятно.

JetBrains dotPeek билд 1.0.0.1219

Наиболее глючный и в то же время наиболее функциональный продукт. Регулярно (но не так часто чтобы надоесть) показывает диалог с просьбой отправить детали ошибки. Несколько раз сталкивался с таким багом. Открываю, например, исходники StringBuilder, затем выбираю интерфейс, который он реализует и исходный текст StringBuilder’а пропадает и больше не появляется. Ниже наглядная демонстрация бага.

image

Из существенных ограничений – умеет только декомпилировать в C#.

Для тех, кто пользуется решарпером интерфейс и горячие клавиши будут знакомы. Жаль, но не работает как в решарпере поиск элемента по заглавным буквам. Отличается и немного терминология. Т.е. нет команды Analyze, но есть Find Usages и Find Usages Advanced.

Нет панели инструментов с кнопками навигации (как-то привык я к нему в рефлекторе), чтобы перемещаться по коду вперед-назад надо выбирать пункта Navigate главного меню, что откровенно говоря не удобно. К счастью для этих команд горячие клавиши такие же как и в студии по дефолту.

Автоматически не выделяется текущий тип в дереве (но есть специальная команда ;)).

Как видно из скриншота каждый тип открывается в новой вкладке. Вкладки можно перемещать и прикреплять аналогично тому как это делается в студии.

Из интересных новшеств подметил, что dotPeek умеет подгружать с сайта Майросовт реальный исходный код (как это делает студия), но у меня почему-то это не сработало (возможно, тоже какой-то дефект).

Выводы

Меньше всех понравился JustDecompile. Оставлю только на случай если понадобится декомпиляция в Visual Basic .NET. Между ILSpy и dotPeek окончательный выбор я так пока не сделал. Я хоть и пользусь решарпером и нравится мне продвинутая функциональнось dotPeek, но как-то в большинстве случаев ILSpy пользоваться удобней. Возможно, сказывается привычка к .NET Reflector, а ILSpy больше всего на него похож.