| входящего документа а также два дополнительных элемента
+-->
<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>
Результат этого преобразования приведен на следующем листинге.
<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 на элементы с.
<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>
<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.
Следующий листинг демонстрирует предложенный подход.
<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 -->