跳过已处理节点的处理

时间:2010-11-18 15:11:15

标签: xslt

有没有办法避免处理已处理的节点?

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <node1>node1.1</node1>
    <node2>node2.1</node2>
    <node2>node2.2</node2>
    <node1>node1.2</node1>
</root>

XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="node1">
        [Node1]:<xsl:value-of select="."></xsl:value-of>
        <xsl:apply-templates select="following-sibling::node2"/>
        [End node1]
    </xsl:template>

    <xsl:template match="node2">
            [Node2]:<xsl:value-of select="."></xsl:value-of>
    </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="UTF-8"?>

        [Node1]:node1.1
            [Node2]:node2.1
            [Node2]:node2.2
        [End node1]

            [Node2]:node2.1

            [Node2]:node2.2

        [Node1]:node1.2
        [End node1]

正如您所见,模板<xsl:template match="node2">对每个node2元素应用两次 - 一次来自node1模板,第二次是XSLT处理器转换node2元素。

是否有任何解决方案可以避免第二次申请xsl:template match="node2"? 当我刚在node1的模板中处理node2时,我需要停止处理node2。

重要 这个例子只是对更复杂的用例的仿真。 这意味着我们有额外的限制 - 我们无法修改根元素处理的模板。

我想知道是否有任何方法可以停止处理元素或将处理移动到其他元素。

3 个答案:

答案 0 :(得分:3)

您可以使用mode命名要使用的模板。

您可以创建一个不会输出任何内容的空的catch-all节点,负责处理没有apply-templates的{​​{1}}个调用。

以下样式表输出您需要的内容:

select

注意最后的空模式模板,以及模板上添加的<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="root"> <xsl:apply-templates/> </xsl:template> <xsl:template match="node1"> [Node1]:<xsl:value-of select="."></xsl:value-of> <xsl:apply-templates select="following-sibling::node2" mode="fromNode1"/> [End node1] </xsl:template> <xsl:template match="node2" mode="fromNode1"> [Node2]:<xsl:value-of select="."></xsl:value-of> </xsl:template> <xsl:template match="node2"></xsl:template> </xsl:stylesheet> 属性和调用mode

答案 1 :(得分:1)

此样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:key name="kNode2ByPrecedingNode1" match="node2"
             use="generate-id(preceding-sibling::node1)"/>
    <xsl:template match="root">
        <xsl:apply-templates select="node1"/>
    </xsl:template>
    <xsl:template match="node1">
        <xsl:value-of select="concat('[Node1]: ',.,'&#xA;')"/>
        <xsl:apply-templates select="key('kNode2ByPrecedingNode1',
                                         generate-id())"/>
        <xsl:text>[End node1]&#xA;</xsl:text>
    </xsl:template>
    <xsl:template match="node2">
        <xsl:value-of select="concat('&#x9;[Node2]: ',.,'&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>

输出:

[Node1]: node1.1
    [Node2]: node2.1
    [Node2]: node2.2
[End node1]
[Node1]: node1.2
[End node1]

注意:两个问题:您多次处理node2,从root规则应用模板到所有节点子项,以及node1规则;加上following-sibling::node2表达式无法区分node2node1 {/ 1}}。

编辑:如果您无法修改root规则应用模板的方式,那么您需要处理和跳过过程的模式:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:key name="kNode2ByPrecedingNode1" match="node2"
             use="generate-id(preceding-sibling::node1)"/>
    <xsl:template match="root">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="node1">
        <xsl:value-of select="concat('[Node1]: ',.,'&#xA;')"/>
        <xsl:apply-templates select="key('kNode2ByPrecedingNode1',
                                         generate-id())"
                             mode="output"/>
        <xsl:text>[End node1]&#xA;</xsl:text>
    </xsl:template>
    <xsl:template match="node2"/>
    <xsl:template match="node2" mode="output">
        <xsl:value-of select="concat('&#x9;[Node2]: ',.,'&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:0)

XSLT不跟踪状态,每个apply-templates,for-each等都可能产生“冗余”结果,但这在样式表的设计中完全是个问题 - 如果你不想“处理”一个节点不止一次需要更改相应的模板并选择,以便不会多次处理它。

这对你的例子来说是相当微不足道的,但是你说你的例子不是很有代表性,所以如果你遇到问题,我建议你发布一些更完整的内容。