XSLT - 将现有节点放在不同的位置并添加动态ID

时间:2015-07-23 14:06:25

标签: xml xslt xslt-2.0

我有xml如下,

<doc>
    <session>
        <a type="abc">
            <b>contetnt</b>
            <c>contetnt</c>
        </a>
        <a type="abc">
            <b>contetnt</b>
            <c>contetnt</c>
        </a>
        <a type="abc">
            <b>contetnt</b>
            <c>contetnt</c>
        </a>
        <d></d>
        <e></e>
        <f></f>
    </session>
</doc>

我的要求是,

1)在节点结束之前添加节点

2)当前文档中的节点应放在新创建的节点

3)将动态增量id添加到节点

所以输出应该是

<doc>
    <session>
        <d></d>
        <e></e>
        <f></f>
        <end>
            <a idNo="1" type="abc">
                <b>contetnt</b>
                <c>contetnt</c>
            </a>
            <a idNo="2" type="abc">
                <b>contetnt</b>
                <c>contetnt</c>
            </a>
            <a idNo="3" type="abc">
                <b>contetnt</b>
                <c>contetnt</c>
            </a>
        </end>
    </session>
</doc>

我写了以下xsl来完成这项任务,

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

    <!-- add dynamic id -->
    <xsl:template match="a">
        <xsl:copy>
            <xsl:attribute name="idNo">
                <xsl:number count="a"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- create <end> node and copy <a> nodes -->
    <xsl:template match="session">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
            <end>endNode</end>
            <xsl:copy-of select="a"/>
        </xsl:copy>
    </xsl:template>

    <!-- remove original <a> nodes-->
    <xsl:template match="a"/>

当我单独运行这些xsl时它们运行正常但是当我运行它们时,我得到一个模糊的模板匹配错误。

我的xsl代码是正确的,但是我有一个问题就是按正确的顺序组织它们来完成我的任务。

任何人都可以建议一种方法来以正确的方式组织这些代码来实现我的任务吗?

1 个答案:

答案 0 :(得分:3)

您有两个完全匹配a的模板,这被视为错误。 XSLT将标记错误,或者可以选择最后一个模板。

解决此问题的一种方法是使用mode属性。将xsl:copy select="a" />更改为使用xsl:apply-templates代替(无论如何,您都应该根据需要进行转换)

 <xsl:apply-templates select="a" mode="end"/>

然后,更改第一个模板匹配也使用此模式。那么你的XSLT将如下所示:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes" />

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

    <!-- add dynamic id -->
    <xsl:template match="a" mode="end">
        <xsl:copy>
            <xsl:attribute name="idNo">
                <xsl:number count="a"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- create <end> node and copy <a> nodes -->
    <xsl:template match="session">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
            <end>
                <xsl:apply-templates select="a" mode="end"/>
            </end>
        </xsl:copy>
    </xsl:template>

    <!-- remove original <a> nodes-->
    <xsl:template match="a"/>
</xsl:stylesheet>

或者,在session模板中,不要处理所有子节点,而是添加代码以忽略此时的a元素

 <xsl:apply-templates select="@*|node()[not(self::a)]"/>

这意味着你不再需要模板来删除它们了。

尝试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes" />

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

    <!-- add dynamic id -->
    <xsl:template match="a">
        <xsl:copy>
            <xsl:attribute name="idNo">
                <xsl:number count="a"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- create <end> node and copy <a> nodes -->
    <xsl:template match="session">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[not(self::a)]"/>
            <end>
                <xsl:apply-templates select="a"/>
            </end>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>