среда, 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.

Комментариев нет: