I.Выполнение цепочки преобразований довольно часто используется в приложениях 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
умножается на два.
См. Также ответ Майкла Кея на ваш первый вопрос, который также объяснил эту общую технику.
II.Решение XSLT 2.0 (без RTF):
<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>
III.Использование compose()
и compose-flist()
функций / шаблонов FXSL
Библиотека FXSL предоставляет две удобные функции / шаблон, которые поддерживают простое сцепление преобразований,Первый объединяет две функции / преобразования, а второй - все функции / преобразования, представленные в последовательности.
Вот простой пример полного кода :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:myFun1="f:myFun1"
xmlns:myFun2="f:myFun2"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="xsl f ext myFun1 myFun2"
>
<xsl:import href="compose.xsl"/>
<xsl:import href="compose-flist.xsl"/>
<!-- to be applied on any xml source -->
<xsl:output method="text"/>
<myFun1:myFun1/>
<myFun2:myFun2/>
<xsl:template match="/">
<xsl:variable name="vFun1" select="document('')/*/myFun1:*[1]"/>
<xsl:variable name="vFun2" select="document('')/*/myFun2:*[1]"/>
Compose:
(*3).(*2) 3 =
<xsl:call-template name="compose">
<xsl:with-param name="pFun1" select="$vFun1"/>
<xsl:with-param name="pFun2" select="$vFun2"/>
<xsl:with-param name="pArg1" select="3"/>
</xsl:call-template>
<xsl:variable name="vrtfParam">
<xsl:copy-of select="$vFun1"/>
<xsl:copy-of select="$vFun2"/>
<xsl:copy-of select="$vFun1"/>
</xsl:variable>
Multi Compose:
(*3).(*2).(*3) 2 =
<xsl:call-template name="compose-flist">
<xsl:with-param name="pFunList" select="ext:node-set($vrtfParam)/*"/>
<xsl:with-param name="pArg1" select="2"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="myFun1:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:value-of select="3 * $pArg1"/>
</xsl:template>
<xsl:template match="myFun2:*" mode="f:FXSL">
<xsl:param name="pArg1"/>
<xsl:value-of select="2 * $pArg1"/>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к любому документу XML (не используется), будут получены нужные, правильные результаты :
Compose:
(*3).(*2) 3 =
18
Multi Compose:
(*3).(*2).(*3) 2 =
36