在XSLT中,我可以只运行一次模板

oil*_*lio 6 xslt

我有一个XSLT块,可以在整个转换过程中多次应用.但我希望它实际上只在第一次应用时运行,它应该被忽略所有的次数.我该怎么做呢?

作为一个例子,这是我想要做的事情:在样式表中我定义了一个全局变量:

<xsl:variable name="run_once" select="0"/>
Run Code Online (Sandbox Code Playgroud)

然后我有一个多次调用的模板:

<xsl:template name="some_template">
    <xsl:if test="$run_once != 1">
        <xsl:variable name="run_once" select="1"/>
        <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text>
    </xsl:if>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

这当然不起作用,因为变量不能改变,只能重载.因此,一旦some_template退出,$ run_once再次为0,并且每次调用模板时都会应用文本.是否有某种类型的ifdef功能或我可以设置的其他全局对象?

如果您对我为什么要这样做感兴趣,下面是对我的问题和我使用的解决方案的更详细的解释:

  • 我的输入是原始XML中的数据,我的输出是WordML格式的报告.
  • 在输入中我有一系列节点(名为theNode).这些节点中的一些(但不是全部)需要在输出中显示.仅当XPATH hairyLogic为true 时才应显示该节点 (hairyLogic显然很长且很复杂).
  • theNode也有一个类型(存储在子节点中).在输入中,所有相同类型的节点将始终组合在一起.在输出中,所有相同类型的节点应该在该类型的特定标题下分组(每种类型应该只有一个标题).

这是我最终使用的解决方案:

...
<xsl:apply-templates select="theNode[hairyLogic]"/>
...

<xsl:template match="theNode">
    <xsl:if test="count(preceding-sibling::theNode[type = current()/type and hairyLogic])=0">
        <xsl:choose>
            <xsl:when test="type = 'TYPE1a' or type = 'TYPE1b'">
                <xsl:call-template name="TYPE1Heading"/>
            </xsl:when>
            <xsl:when test="type = 'TYPE2'">
                <xsl:call-template name="TYPE2Heading"/>
            </xsl:when>
        </xsl:choose>
    </xsl:if>
    ...
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

我选择使用命名模板作为标题,因为它们包含不依赖于输入XML中任何数据的基本WordML.

我不喜欢这个解决方案,因为hairyLogic被重复并且if语句很复杂且难以阅读.也许你有一个更好的解决方案,不需要可变变量?

Chr*_*ott 2

我建议使用匹配模板而不是命名模板,因为它更像是,Pythonic的 XSLT 等价物是什么?Xslt-y?我想您会发现使用这种处理方法可以更轻松地解决问题。

如果您由于某些未知的需求而坚持使用命名模板,您可能会发现,如果您重构逻辑以使其易于检测第一个实例,您将完全简化您的逻辑。

您能否澄清一下为什么在需要第一个实例时无法检测到?我们或许可以帮助您制作一个 xpath 表达式,让您可以按照自己的意愿行事。例如

<xsl:template name="some_template">
    <xsl:variable name="EXPRESSION" select=".[somelogic='true']"/>
    <xsl:if test="$EXPRESSION">
        <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text>
    </xsl:if>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

由于 XSLT 是确定性的 - 正如 Greg 所说的那样,功能齐全的效果 - (除非您正在做奇怪的扩展),您可以通过对输入应用逻辑来决定第一次何时合适。此外,您还可以访问模板中的上下文节点,以便知道从哪里调用它。