Выполнение цепочки преобразований используется довольно часто в XSLT приложениях, хотя делает это полностью в XSLT 1.0 требует использования xxx:node-set()
функции конкретного производителя. В XSLT 2.0 такое расширение не требуется, поскольку там печатается печально известный тип RTF.
Вот пример (слишком просто, чтобы быть значимым, но иллюстрирующий полностью, как это делается):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="/*/*"/>
</xsl:variable>
<xsl:variable name="vPass1"
select="ext:node-set($vrtfPass1)"/>
<xsl:apply-templates mode="pass2"
select="$vPass1/*"/>
</xsl:template>
<xsl:template match="num[. mod 2 = 1]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="num" mode="pass2">
<xsl:copy>
<xsl:value-of select=". *2"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется на следующий документ XML:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
Требуется, правильный результат:
<num>2</num>
<num>6</num>
<num>10</num>
<num>14</num>
<num>18</num>
Объяснение:
На первом этапе XML-документ преобразуется и результат определяется как значение переменной $vrtfPass1
. Это копирует только элементы num
, которые имеют нечетное значение (даже не).
$vrtfPass1
переменных, будучи тип RTF, не может непосредственно использоваться для XPath-выражения поэтому мы преобразуем его в нормальное дерево, используя EXSLT (реализованное большинство XSLT 1.0 процессоров) функции ext:node-set
и определяющего другие переменным - - $vPass1
, значение которого - это дерево.
теперь выполнить второе преобразование в нашей цепочке превращений - на результате первого преобразования, которая сохраняется как значение переменной $vPass1
. Чтобы не путаться с шаблоном первого прохода, мы указываем, что новая обработка должна быть в именованном режиме, называемом «pass2». В этом режиме значение любого элемента num
умножается на два.
XSLT 2.0 решение (без RTFS):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vPass1" >
<xsl:apply-templates select="/*/*"/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="$vPass1/*"/>
</xsl:template>
<xsl:template match="num[. mod 2 = 1]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="num" mode="pass2">
<xsl:copy>
<xsl:value-of select=". *2"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Хороший вопрос, +1. См. Мой ответ для объяснения и полный пример кода. :) –
Да, это принято, но не всегда необходимо. Если вы используете Java, Transformerfactory может быть настроен на последовательные преобразования подбородка и избегать ненужных операций синтаксического анализа. http://stackoverflow.com/questions/1312406/efficient-xslt-pipeline-in-java-or-redirecting-results-to-sources/1319774#1319774 –