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

XSLT - place existing node in different position and add dynamic ids

我有 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 代码是正确的,但我在按正确的顺序组织它们以完成我的任务时遇到了问题。

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

您有两个模板与 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>