XSLT - 添加新属性和节点

时间:2015-07-17 06:16:14

标签: xml xslt xslt-2.0

我有一个xml如下,

<doc>
    <a type="atr111"></a>
    <a type="atr111"></a>
    <a type="atr111"></a>
    <a type="atr222"></a>
    <a type="atr222"></a>
    <a type="atr222"></a>
</doc>

我的要求是,

  1. 将动态增量id属性添加到具有属性atr111atr222
  2. 的节点
  3. 在节点内添加新节点,名为<newNode>,其属性id="newAttr"具有属性atr111atr222
  4. <a>个节点属性值atr111更改为atr222
  5. 所以我的预期输出是,

    <doc>
        <a id="id-1" type="atr222"><newNode id="newAttr"/></a>
        <a id="id-2" type="atr222"><newNode id="newAttr"/></a>
        <a id="id-3" type="atr222"><newNode id="newAttr"/></a>
        <a id="id-4" type="atr222"><newNode id="newAttr"/></a>
        <a id="id-5" type="atr222"><newNode id="newAttr"/></a>
        <a id="id-6" type="atr222"><newNode id="newAttr"/></a>
    </doc>
    

    我写的xsl是为了得到那些输出,

    <xsl:template match="a" priority="1">
            <!-- add new dynamic id -->
          <xsl:copy>
                <xsl:attribute name="id">
                    <xsl:value-of select="'id-'"/> 
                    <xsl:number count="a[@type='atr111' or @type='atr222']" level="any"/>
                </xsl:attribute>
            </xsl:copy>
    
            <!-- add newNode inside <a> node -->
            <xsl:copy>
            <newNode>
                <xsl:attribute name="id">newAttr</xsl:attribute>
            </newNode>
          </xsl:copy>
        </xsl:template>
    
        <!-- change existing 'atr111' attribute value to 'atr222' -->
        <xsl:template match="a/@type[. = 'atr111']">
            <xsl:attribute name="type">atr222</xsl:attribute>
        </xsl:template>  
    

    我目前的输出如下,

    <doc>
        <a id="id-1"/><a><newNode id="newAttr"/></a>
        <a id="id-2"/><a><newNode id="newAttr"/></a>
        <a id="id-3"/><a><newNode id="newAttr"/></a>
        <a id="id-4"/><a><newNode id="newAttr"/></a>
        <a id="id-5"/><a><newNode id="newAttr"/></a>
        <a id="id-6"/><a><newNode id="newAttr"/></a>
    </doc>
    

    正如您所见,动态ID已按预期添加,并且还添加了具有新属性的<newNode>。但它已复制<a>节点。现有属性type也已消失。

    如何组织代码以获得预期的输出?

1 个答案:

答案 0 :(得分:1)

您忘记复制type属性。 <xsl:copy>仅复制当前节点本身,而不复制其子节点或属性。

以下内容使用身份模板进行复制子项和属性的过程。

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output encoding="UTF-8" indent="yes" />

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

    <xsl:template match="a[@type='atr111' or @type='atr222']">
        <xsl:copy>
            <xsl:attribute name="id">
                <xsl:text>id-</xsl:text>
                <xsl:number count="a[@type='atr111' or @type='atr222']" level="any" />
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()" />
            <newNode id="newAttr" />
        </xsl:copy>
    </xsl:template>
</xsl:transform>

输出:

<doc>
    <a id="id-1" type="atr111"><newNode id="newAttr"/></a>
    <a id="id-2" type="atr111"><newNode id="newAttr"/></a>
    <a id="id-3" type="atr111"><newNode id="newAttr"/></a>
    <a id="id-4" type="atr222"><newNode id="newAttr"/></a>
    <a id="id-5" type="atr222"><newNode id="newAttr"/></a>
    <a id="id-6" type="atr222"><newNode id="newAttr"/></a>
</doc>

如果没有其他孩子,你当然也可以使用<xsl:copy-of select="@type" />,但灵活性较差:通过身份模板进行复制可以让你携带变量输入并添加,例如, <xsl:template match="a/@type">稍后会根据需要对@type个节点进行一些特殊处理。