XSLT - 将节点复制到新位置并删除原始节点

时间:2015-07-24 01:44:11

标签: xml xslt xpath xslt-2.0

我有一个xml如下,

<session>
    <foot>
        <p type="note">
            <link ref="http://www.facebook.com">
                <c type="Hyperlink">www.faceook.com</c>
            </link>
        </p>
    </foot>
    <foot>
        <p type="note">
            <link ref="http://www.google.com">
                <c type="Hyperlink">www.google.com</c>
            </link>
        </p>
    </foot>
    <middle>

    </middle>
    <middle>

    </middle>
</session>

我的要求是,

1)向<p>节点添加动态ID,其属性值为type="note"

2)在<newNode>节点内名为<p>的新节点,其属性值为type="note"

3)为新创建的<newNode>

添加动态ID

4)在<Finish>个节点结束之前添加一个<session>节点,该节点至少包含节点<foot>节点

5)复制节点和节点之间的所有<foot>节点

6)摆脱原始的<foot>节点

所以输出应该是,

<session>

    <middle>

    </middle>
    <middle>

    </middle>
    <Finish type="Endnotes">End</Finish><foot>
        <p id="id-1" type="note">
            <link ref="http://www.facebook.com">
                <c type="Hyperlink">www.faceook.com</c>
            </link>
            <newNode refType="middle" ref="id-1"/></p>
    </foot><foot>
        <p id="id-2" type="note">
            <link ref="http://www.google.com">
                <c type="Hyperlink">www.google.com</c>
            </link>
            <newNode refType="middle" ref="id-2"/></p>
    </foot>
   </session>

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

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

    <!-- create dynamic id in <p> node -->
    <xsl:template match="p[@type='note']">
        <xsl:copy>
            <xsl:attribute name="id">
                <xsl:value-of select="'id-'"/> 
                <xsl:number count="p[@type='note']" level="any"/>
            </xsl:attribute>

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

            <!-- add new node named <newNode> in <foot> -->
            <newNode refType="middle">
                <xsl:attribute name="ref">
                    <xsl:value-of select="'id-'"/>
                    <xsl:number count="p[@type='note']" level="any"></xsl:number>
                </xsl:attribute>
            </newNode>
        </xsl:copy>
    </xsl:template>

    <!-- select session which has <foot> nodes -->
    <xsl:template match="session[.//foot]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <!-- create <Finish> node just before </session> -->
            <Finish type="Endnotes">End</Finish>
            <!-- copy <foot> node between <Finish> and </session> -->
            <xsl:apply-templates select="current()//foot"/>
        </xsl:copy>
    </xsl:template>

    <!-- get rid of original <foot> nodes-->
    <xsl:template match="session//foot"/>

我遇到的唯一问题是,当我写<xsl:template match="session//foot"/>来删除原始<foot>节点时,它会删除每个<foot>复制到新位置的节点。

任何人都可以建议一种方法,使<foot>节点保持复制到新位置并删除原始<foot>节点。

提前致谢

1 个答案:

答案 0 :(得分:1)

  

我遇到的唯一问题是当我写<xsl:template match="session//foot"/>以删除它删除的原始<foot>节点时   每个<foot>也会复制到新的地方。

那是因为你正在使用:

<xsl:apply-templates select="current()//foot"/>

放置节点。这再次适用于您编写的空模板,因此不会输出任何内容。你应该使用:

<xsl:copy-of select="current()//foot"/>

或:

<xsl:apply-templates select="current()//foot" mode="move"/>

并使用相同的模式编写另一个匹配foot的模板来处理它。

第三个选项是完全删除匹配foot的空模板,而在应用模板时更具选择性。而不是:

<!-- select session which has <foot> nodes -->
<xsl:template match="session[.//foot]">
    <xsl:copy>
        <xsl:apply-templates select="@*|node() "/>

做的:

<!-- select session which has <foot> nodes -->
<xsl:template match="session[.//foot]">
    <xsl:copy>
        <xsl:apply-templates select="@*|node() except foot"/>

这假定foot始终是session的孩子,如示例所示。您的样式表显然也希望在其他地方使用它(否则为什么要使用//中的.//foot),因此您可能需要在更多地方添加类似的异常。