Выбрать главу

   | входящего документа а также два дополнительных элемента

   +-->

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

   <xsclass="underline" copy-of select="item"/>

   <item>RUS</item>

   <item>UKR</item>

  </xsclass="underline" variable>

  <!--

   | Конвертируем переменную tree во множество узлов,

   | результат присваиваем переменной items

   +-->

  <xsclass="underline" variable name="items" select="xalan:nodeset($tree)"/>

  <!--

   | Обрабатываем узлы $items/item точно так же,

   | как мы обрабатывали бы узлы items/item

   +-->

  <select name="language">

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

    <option>

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

    </option>

   </xsclass="underline" for-each>

  </select>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Результат этого преобразования приведен на следующем листинге.

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

<select name="language">

 <option>ENG</option>

 <option>FRE</option>

 <option>GER</option>

 <option>GRE</option>

 <option>ITA</option>

 <option>NOR</option>

 <option>POR</option>

 <option>SPA</option>

 <option>USA</option>

 <option>RUS</option>

 <option>UKR</option>

</select>

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

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

В качестве примера рассмотрим схему трансформации, изображенную на рис. 10.3, в которой документ А сначала нужно обработать преобразованием 1, затем полученный результат (документ В) обработать преобразованием 2. Конечным результатом цепочки преобразований в данном случае является документ С.

Рис. 10.3. Двухшаговое преобразование

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

Пример

Представим себе два простых преобразования, first.xsl и second.xsl, первое из которых заменяет во входящем документе элементы а на элементы b, а второе — элементы b на элементы с.

Листинг 10.13. Преобразование first.xsl

<xsclass="underline" stylesheet

 version="1.0"

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

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

  <b>

   <xsclass="underline" apply-templates select="@*|node()"/>

  </b>

 </xsclass="underline" template>

 <xsclass="underline" template match="@*|node()">

  <xsclass="underline" copy>

   <xsclass="underline" apply-templates select="@*|node()"/>

  </xsclass="underline" copy>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Листинг 10.14. Преобразование second.xsl

<xsclass="underline" stylesheet

 version="1.0"

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

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

  <c>

   <xsclass="underline" apply-templates select="@*|node()"/>

  </c>

 </xsclass="underline" template>

 <xsclass="underline" template match="@*|node()">

  <xsclass="underline" copy>

   <xsclass="underline" apply-templates select="@*|node()"/>

   </xsclass="underline" copy>

  </xsclass="underline" template>

</xsclass="underline" stylesheet>

Для того чтобы последовательно применить два этих преобразования к некоторому входящему документу a.xml, мы можем, например, дважды вызвать процессор:

java org.apache.xalan.xslt.Process -IN a.xml -XSL first.xsl -OUT b.xml

java org.apache.xalan.xslt.Process -IN b.xml -XSL second.xsl -OUT c.xml

В результате этих вызовов XSLT-процессор Xalan сначала применит преобразование first.xsl к документу a.xml и сохранит результат в файле b.xml, а затем обработает полученный документ b.xml при помощи преобразования second.xml и сохранит результат в файле c.xml.

В качестве альтернативы, например, для тех случаев, когда пакетная обработка невозможна, мы можем создать преобразование, последовательно применяющее шаблоны преобразований first.xsl и second.xsl к входящему документу. Для этого:

□ назначим шаблонам преобразования first.xsl режим first, а шаблонам преобразования second.xsl — режим second;

□ в основном шаблоне применим шаблоны режима first к узлам входящего документа, сохранив результат в переменной b;

□ приведем результирующее дерево, содержащееся в переменной b ко множеству узлов;

□ обработаем полученное множество узлов шаблонами режима second.

Следующий листинг демонстрирует предложенный подход.

Листинг 10.5. Преобразование first-then-second.xsl

<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">

 <!-- Шаблоны преобразования first -->

 <xsclass="underline" template match="a" mode="first">

  <b>

   <xsclass="underline" apply-templates select="@*|node()" mode="first"/>

  </b>

 </xsclass="underline" template>

 <xsclass="underline" template match="@*|node()" mode="first">

  <xsclass="underline" copy>

   <xsclass="underline" apply-templates select="@*|node()" mode="first"/>

  </xsclass="underline" copy>

 </xsclass="underline" template>

 <!-- Шаблоны преобразования second -->