我正在修改一个已经附带一些模板的XSL,这些模板输出相对于当前上下文节点的数据。我想使用不同的上下文调用相同的模板,因此我不必通过传递其他参数来更改现有模板。
例如XML:
<anyRoot>
<level1>
<a>xxxxxx</a>
<b>yyyyyy</b>
<level2>
<a>aaaaa</a>
<b>bbbbbb</b>
<c>cccccc</c>
<d>dddddd</d>
</level2>
</level1>
<level1>
<a>zzzzzz</a>
<b>jjjjjj</b>
<level2>
<a>nnnnn</a>
<b>bbbbbb</b>
<c>cccccc</c>
<d>dddddd</d>
</level2>
</level1>
</anyRoot>
理论XSL。请注意&#34; context =&#34;属性无效但我把它放在那里解释我的想法:
...
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:call-template name="testTmplate"/>
<xsl:call-template name="testTmplate" context=".."/> <!-- passing parent of level2-->
</xsl:for-each>
...
<xsl:template name="testTmplate">
<xsl:value-of select="./a"/>
</xsl:template>
这就是我想看到的输出:
aaaaa
xxxxxxx
nnnnnnn
zzzzzzz
答案 0 :(得分:2)
如果你想改变上下文,你应该在这里使用xsl:apply-templates
,并使用匹配的模板。
例如
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:apply-templates select="a" />
<xsl:apply-templates select="../a" />
</xsl:for-each>
</xsl:template>
<xsl:template match="a">
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
但是,如果您的实际XSLT中还有另一个模板也匹配“a”元素,您可以使用mode
属性区分所需的模板,如下所示:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:apply-templates select="a" mode="testTmplate" />
<xsl:apply-templates select="../a" mode="testTmplate" />
</xsl:for-each>
</xsl:template>
<xsl:template match="a" mode="testTmplate">
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
编辑:如果您真的想要调用此方法的现有名称模板,只需从匹配的模板中调用它。试试这个......
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:call-template name="testTmplate"/>
<xsl:apply-templates select=".." mode="testTmplate" />
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="testTmplate">
<xsl:call-template name="testTmplate"/>
</xsl:template>
<xsl:template name="testTmplate">
<xsl:value-of select="a"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
原始./
中的./a
是多余的,正如@ tim-c所说,使用xsl:apply-templates
可能会更好。但是,如果您不想使用现有的xsl:call-template
和命名模板设置过多,您可以添加默认为上下文节点的参数(例如,$context
),然后覆盖必要时:
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:call-template name="testTmplate"/>
<xsl:call-template name="testTmplate">
<xsl:param name="context" select=".."/> <!-- passing parent of level2-->
</xsl:call-template>
</xsl:for-each>
...
<xsl:template name="testTmplate">
<xsl:param name="context" select="."/>
<xsl:value-of select="$context/a"/>
</xsl:template>
因此./a
变得更有用$context/a
。
答案 2 :(得分:0)
下面错误的方式!请参阅蒂姆的答案,了解正确的方法。但是,假设您已命名模板,您无法或不会更改,并且您希望重复使用它们,请参阅下文。当然,根据您当前的代码,您可以向模板添加参数,或者更好地使用带模式的未命名模板。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:call-template name="testTmplate"/>
</xsl:for-each>
<xsl:for-each select="/anyRoot/level1">
<xsl:call-template name="testTmplate"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="testTmplate">
<xsl:value-of select="./a"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
答案 3 :(得分:0)
不会更改现有命名模板的方法是使用xsl:for-each
更改上下文:
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:call-template name="testTmplate"/>
<xsl:for-each select=".."> <!-- parent of level2 -->
<xsl:call-template name="testTmplate"/>
</xsl:for-each>
</xsl:for-each>
我毫不犹豫地推荐这个,因为IMO,它不具有可读性,但是使用$context
乱扔许多模板可能最终也不那么可读。
答案 4 :(得分:0)
谢谢蒂姆。你的答案游戏是一个非常重要的线索,所以我最终为第二个模板调用添加了一个新模板(从父项中提取数据的模板)。此新模板充当包装器模板以调用现有模板。见下面的答案。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="/anyRoot/level1/level2">
<xsl:call-template name="testTemplate" />
<xsl:apply-templates select=".." mode="testTemplateWrapper" />
</xsl:for-each>
</xsl:template>
<xsl:template name="testTemplate">
<xsl:value-of select="a"/>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="level1" mode="testTemplateWrapper">
<xsl:call-template name="testTemplate" />
</xsl:template>
</xsl:stylesheet>