XSLT - применить шаблон к результату шаблона вызова
Можно ли применить шаблон к результату call-шаблона?
Например, xml и 2 xslt ниже.
index.xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<book>
<title>Ethics</title>
</book>
<book>
<title>Beyond Good and Evil</title>
</book>
</root>
index2.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/" name="temp2">
<foo>
<xsl:for-each select="//book">
<bar><xsl:value-of select="."/></bar>
</xsl:for-each>
</foo>
</xsl:template>
</xsl:stylesheet>
и index.xsl вызывает index2.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:include href="index2.xsl" />
<!-- apply a template to the <xsl:call-template name="temp2" /> result -->
</xsl:stylesheet>
Есть ли способ применить шаблон к результату <xsl:call-template name="temp2" />
в index.xsl?
Заранее спасибо.
1 ответ
Есть ли способ применить шаблон к результату
<xsl:call-template name="temp2" />
в index.xsl?
Да, это называется многопроходной обработкой. Единственная особенность заключается в том, что в XSLT 1.0 вы должны применять зависящие от реализации xxx:node-set()
функция расширения для любого промежуточного результата, который в общем случае будет иметь печально известный тип RTF (Result Tree Fragment) и, следовательно, должен быть преобразован в обычное дерево.
Вот полный пример многопроходной обработки (я использую xsl:apply-templates
и не xsl:call-template
, но вы можете свободно изменять этот пример, чтобы использовать именованные шаблоны и xsl:call-template
вместо):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="num"/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="ext:node-set($vrtfPass1)/*"/>
</xsl:template>
<xsl:template match="num">
<num><xsl:value-of select="2* ."/></num>
</xsl:template>
<xsl:template match="num" mode="pass2">
<num><xsl:value-of select=". * ."/></num>
</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
элементы удваиваются в первом проходе, затем возводятся в квадрат во втором проходе):
<num>4</num>
<num>16</num>
<num>36</num>
<num>64</num>
<num>100</num>
<num>144</num>
<num>196</num>
<num>256</num>
<num>324</num>
<num>400</num>
II. В XSLT 2.0
"Тип" RTF был упразднен, поэтому намного проще указать многопроходную обработку, которая становится практически неотличимой от функциональной композиции, как показывает следующее эквивалентное преобразование:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:sequence select="my:squareAll(my:doubleAll(*))"/>
</xsl:template>
<xsl:function name="my:doubleAll" as="element()*">
<xsl:param name="pElems" as="element()*"/>
<xsl:for-each select="$pElems">
<xsl:copy>
<xsl:sequence select=". + ."/>
</xsl:copy>
</xsl:for-each>
</xsl:function>
<xsl:function name="my:squareAll" as="element()*">
<xsl:param name="pElems" as="element()*"/>
<xsl:for-each select="$pElems">
<xsl:copy>
<xsl:sequence select=". * ."/>
</xsl:copy>
</xsl:for-each>
</xsl:function>
</xsl:stylesheet>
когда это преобразование применяется к тому же XML-документу (см. выше), получается тот же правильный результат:
<num>4</num>
<num>16</num>
<num>36</num>
<num>64</num>
<num>100</num>
<num>144</num>
<num>196</num>
<num>256</num>
<num>324</num>
<num>400</num>