使用不同的上下文调用xsl模板

时间:2015-10-15 16:13:01

标签: xml xslt xsl-fo

我正在修改一个已经附带一些模板的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

5 个答案:

答案 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>&#10;</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>&#10;</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>&#10;</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>&#10;</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>&#10;</xsl:text>
    </xsl:template>

    <xsl:template match="level1" mode="testTemplateWrapper">
        <xsl:call-template name="testTemplate" />
    </xsl:template>

</xsl:stylesheet>