Выбрать главу
Пример

Для того чтобы обеспечить работоспособность расширения, реализованного классом de.fzi.xslt.rot в наиболее распространенных XSLT-процессорах, написанных на Java (как-то: Saxon, Xalan и Oracle XSLT Processor), прежде всего необходимо объявить соответствующие пространства имен:

<xsclass="underline" stylesheet

 version="1.0"

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

 xmlns="http://www.w3.org/2000/svg"

 xmlns:saxon="java:de.fzi.xslt.rot"

 xmlns:xalan="xalan://de.fzi.xslt.rot"

 xmlns:oracle="http://www.oracle.com/XSL/Transform/java/de.fzi.xslt.rot"

 exclude-result-prefixes="saxon xalan oracle">

...

Префикс saxon соответствует интерфейсу расширений в XSLT-процессоре Saxon, префикс xalan — процессору Xalan и префикс oracle — Oracle XSLT Processor.

Теперь осталось только найти поддерживаемый вариант расширения и произвести соответствующий вызов.

Листинг 10.9

<xsclass="underline" choose>

 <xsclass="underline" when test="function-available('saxon:X') ">

  <line

   x1="{saxon:X($x1, $y1, $alpha) + 100}"

   y1="{saxon:Y($x1, $y1, $alpha) + 100}"

   x2="{saxon:X($x2, $y2, $alpha) + 100}"

   y2="{saxon:Y($x2, $y2, $alpha) + 100}"/>

 </xsclass="underline" when>

 <xsclass="underline" when test="function-available('xalan:X')">

  <line

   x1="{xalan:X($x1, $y1, $alpha) + 100}"

   y1="{xalan:Y($x1, $y1, $alpha) + 100}"

   x2="{xalan:X($x2, $y2, $alpha) + 100}"

   y2="{xalan:Y($x2, $y2, $alpha) + 100}"/>

 </xsclass="underline" when>

 <xsclass="underline" when test="function-available('oracle:X')">

  <line

   x1="{oracle:X($x1, $y1, $alpha) + 100}"

   y1="{oracle:Y($x1, $y1, $alpha) + 100}"

   x2="{oracle:X($x2, $y2, $alpha) + 100}"

   y2="{oracle:Y($x2, $y2, $alpha) + 100}"/>

 </xsclass="underline" when>

 <xsclass="underline" otherwise>

  <xsclass="underline" message terminate="yes">

   <xsclass="underline" text>Necessary extension function is not available.</xsclass="underline" text>

   <xsclass="underline" text>&#xA;Supported processors are:</xsclass="underline" text>

   <xsclass="underline" text>&#xA;Saxon, Xalan, Oracle XSLT Processor.</xsclass="underline" text>

  </xsclass="underline" message>

 </xsclass="underline" otherwise>

</xsclass="underline" choose>

В случае, если хотя бы одна из функций saxon:X, xalan:X, oracle:X будет доступна при обработке, она будет использована процессором для создания атрибутов элемента line. В противном случае, процессор прервет выполнение преобразования и выведет указанное в элементе xsclass="underline" message сообщение.

Нельзя не согласиться с тем, что приведенный выше способ не отличается элегантностью. Реализовывать свой вариант для каждого существующего процессора может быть довольно трудоемкой задачей — но такова уж плата за возможности расширений.

Функция расширения nodeset

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

Предположим, что мы создаем в переменной rtf результирующий фрагмент дерева следующего вида:

<xsclass="underline" variable name="rtf">

 <item>1</item>

 <item>2</item>

 <item>3</item>

</xsclass="underline" variable>

При попытке вычислить выражение вида $rtf/item[2] процессор в соответствии со спецификацией должен вывести ошибку, поскольку в этом фильтрующем выражении (см. продукцию [XP20] FilterExpr) переменная rtf должна содержать множество узлов, а не фрагмент дерева.

Текущая спецификация языка XPath совершенно явно говорит о том, что ни один тип данных не может быть преобразован во множество узлов. Функция nodeset действует в обход этого запрещения: она принимает на вход результирующий фрагмент дерева и возвращает множество, состоящее из корневого узла этого фрагмента.

В разных процессорах эта функция имеет различный синтаксис: она может носить имя nodeset или node-set, или nodeSet, однако семантика ее во всех случаях одинакова:

nodeset nodeset(result-tree-fragment)

Функция принимает на вход единственный аргумент, являющийся фрагментом дерева и возвращает множество узлов, состоящее из его корня.

Пример

Предположим, что мы обрабатываем входящий документ, содержащий трехбуквенные коды языков.

Листинг 10.10. Входящий документ

<items>

 <item>ENG</item>

 <item>FRE</item>

 <item>GER</item>

 <item>GRE</item>

 <item>ITA</item>

 <item>NOR</item>

 <item>POR</item>

 <item>SPA</item>

</items>

Фрагмент шаблона, обрабатывающий этот список, может выглядеть следующим образом:

<select name="language">

 <xsclass="underline" for-each select="items/item">

  <option>

   <xsclass="underline" value-of select="."/>

  </option>

 </xsclass="underline" for-each>

</select>

Если в преобразовании нам понадобится доопределить входящий список кодами RUS и UKR, не исправляя входящий документ, можно поступить следующим образом:

□ создать в переменной фрагмент дерева, содержащий элементы item входящего документа плюс элементы item, доопределяющие этот список;

□ преобразовать дерево в список узлов;

□ обрабатывать список узлов точно так же, как мы бы обрабатывали сам входящий документ.

Преобразование, реализующее эти три шага, приведено ниже.

Листинг 10.11. Преобразование

<xsclass="underline" stylesheet

 version="1.0"

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

 xmlns:xalan="http://xml.apache.org/xalan"

 exclude-result-prefixes="xalan">

 <xsclass="underline" template match="items">

  <!--

   | Создаем переменную tree, содержащую элементы item