基于输出树的 XSLT 条件

XSLT condition based on output tree

我习惯于在我的 XSLT 中设置基于输入中的节点树的条件。但我想根据输出来做。有什么办法吗?

这是一个例子。

输入:

<top>
    <a>
        <z>
            <item>
                <id>4</id>
            </item>
            <item>
                <id>5</id>
            </item>
        </z>
    </a>
</top>

期望的输出:

<thing>
    <upper>
        <a>
            <z>
                <item>
                    <id>upper-4</id>
                </item>
                <item>
                    <id>upper-5</id>
                </item>
            </z>
        </a>
    </upper>
    <lower>
        <a>
            <z>
                <item>
                    <id>lower-4</id>
                </item>
                <item>
                    <id>lower-5</id>
                </item>
            </z>
        </a>
    </lower>
</thing>

请注意,树基本上是向下复制的,唯一的变化是 id 节点的值已根据我们是在 upper 还是 [=15] 中进行了修改=] 树.

我当前的 XSLT:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:template match="top">
        <thing>
            <upper>
                <xsl:apply-templates />
            </upper>
            <lower>
                <xsl:apply-templates />
            </lower>
        </thing>
    </xsl:template>

    <xsl:template match="id">
        <!-- I want to prepend this with "upper" or "lower" depending which block we're in -->
        <xsl:value-of select="text()" />
    </xsl:template>

    <!-- identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

这是一个简化的例子,在az之间的树中有很多节点,item节点可以出现在a下的各种深度.

最初我从一个看起来像 ancestor::upper 的条件开始,但显然这不起作用,因为 upper 在输出中,而不是输入中。

我也考虑过尝试传递一个参数来说明我们是在 upper 还是 lower,但这意味着更新每个模板(包括身份模板)以具有一个参数并将其传递给它调用的任何模板。如果可能的话,我真的很想避免这种情况。

因此,如果有一种方法可以将变量传递给被调用的模板而无需声明变量,那将是可行的。或者,如果我可以编写一个条件来查看调用我们的模板或我们上方树中的输出,那将起作用。或者还有其他方法吗?

请注意,我使用的是 Saxon 处理器,因此我可以使用特定于它的功能(例如,如果有帮助,我可以调用一些 java)。

谢谢。

这是一个使用 XSLT 2.0 隧道参数的解决方案:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs">

    <!-- identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="top">
        <thing>
            <upper>
                <xsl:apply-templates>
                  <xsl:with-param name="tree-id" tunnel="yes" select="'upper-'"/>
                </xsl:apply-templates>
            </upper>
            <lower>
                <xsl:apply-templates>
                  <xsl:with-param name="tree-id" tunnel="yes" select="'lower-'"/>
                </xsl:apply-templates>
            </lower>
        </thing>
    </xsl:template>

    <xsl:template match="id">
        <xsl:param name="tree-id" tunnel="yes"/>
        <xsl:copy>
          <!-- I want to prepend this with "upper" or "lower" depending which block we're in -->
          <xsl:value-of select="concat($tree-id, .)" />
        </xsl:copy>
    </xsl:template>


</xsl:stylesheet>