XSLT:向rootnode

时间:2016-10-14 15:22:34

标签: xml xslt xslt-1.0

我有以下xml文档:

$ cat data.xml
<rootnode>
 <section id="1" >
  <outer param="p1">
   <inner />
   <inner />
  </outer>
  <outer param="p1">
   <inner />
  </outer>
  <outer />
  <outer param="p5"/>
 </section>
 <section id="2" >
  <outer >
   <inner anotherparam="ap1"/>
   <inner param="p4"/>
   <inner />
  </outer>
 </section>
</rootnode>

我想为每个元素添加一个新属性,rootnode除外。这个XSLT转换几乎完全符合我的要求:

$ cat add.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

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

</xsl:stylesheet>

但是,它还会将新属性添加到rootnode。 如何省略rootnode以便将其复制?

3 个答案:

答案 0 :(得分:3)

我建议你这样做:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="*[not(self::rootnode)]">
    <xsl:copy>
        <xsl:attribute name="newattribute">NEW</xsl:attribute>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:3)

  

我想为每个节点添加一个新属性,但rootnode除外。

我相信你想要不添加属性的唯一元素是document(top)元素。 发生在此XML文档中被命名为rootnode,但在另一个文档中,它可能具有不同的名称,如topnode,并且您希望解决方案在这种情况下也可以工作

此外,如果您有一个名为rootnode的元素不是顶级元素,您可能也希望将新属性添加到此元素中。

因此,无论文档元素的名称是什么,以下转换都会执行此操作

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

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

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

请注意覆盖模板的匹配模式:

  <xsl:template match="*/*">

这匹配其父节点也是元素的每个元素 - 有效地排除顶部(文档)元素。

在提供的XML文档上应用转换时

<rootnode>
    <section id="1" >
        <outer param="p1">
            <inner />
            <inner />
        </outer>
        <outer param="p1">
            <inner />
        </outer>
        <outer />
        <outer param="p5"/>
    </section>
    <section id="2" >
        <outer >
            <inner anotherparam="ap1"/>
            <inner param="p4"/>
            <inner />
        </outer>
    </section>
</rootnode>

产生了想要的正确结果

<rootnode>
    <section newattribute="NEW" id="1">
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW"/>
        <outer newattribute="NEW" param="p5"/>
    </section>
    <section newattribute="NEW" id="2">
        <outer newattribute="NEW">
            <inner newattribute="NEW" anotherparam="ap1"/>
            <inner newattribute="NEW" param="p4"/>
            <inner newattribute="NEW"/>
        </outer>
    </section>
</rootnode>

当转化 - 没有任何更改 - 应用于类似文档(仅将文档元素重命名为topnode)时:

<topnode>
    <section id="1" >
        <outer param="p1">
            <inner />
            <inner />
        </outer>
        <outer param="p1">
            <inner />
        </outer>
        <outer />
        <outer param="p5"/>
    </section>
    <section id="2" >
        <outer >
            <inner anotherparam="ap1"/>
            <inner param="p4"/>
            <inner />
        </outer>
    </section>
</topnode>

再次生成正确的结果

<topnode>
    <section newattribute="NEW" id="1">
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW"/>
        <outer newattribute="NEW" param="p5"/>
    </section>
    <section newattribute="NEW" id="2">
        <outer newattribute="NEW">
            <inner newattribute="NEW" anotherparam="ap1"/>
            <inner newattribute="NEW" param="p4"/>
            <inner newattribute="NEW"/>
        </outer>
    </section>
</topnode>

如果有这个源XML文档(添加了一个不是顶级元素的<rootnode>元素):

<rootnode>
    <section id="1" >
        <outer param="p1">
            <inner />
            <inner />
        </outer>
        <outer param="p1">
            <inner />
        </outer>
        <outer />
        <outer param="p5"/>
    </section>
    <rootnode/>
    <section id="2" >
        <outer >
            <inner anotherparam="ap1"/>
            <inner param="p4"/>
            <inner />
        </outer>
    </section>
</rootnode>

同样,正确的结果是由相同的未更改的转换产生的

<rootnode>
    <section newattribute="NEW" id="1">
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW"/>
        <outer newattribute="NEW" param="p5"/>
    </section>
    <rootnode newattribute="NEW"/>
    <section newattribute="NEW" id="2">
        <outer newattribute="NEW">
            <inner newattribute="NEW" anotherparam="ap1"/>
            <inner newattribute="NEW" param="p4"/>
            <inner newattribute="NEW"/>
        </outer>
    </section>
</rootnode>

需要学习的课程

指定精确匹配模式可以为您节省大量工作!

答案 2 :(得分:1)

如果你添加一个与rootnode匹配的xsl模板,并且与你在@*|node()匹配时所做的类似,那么它就不会添加该属性。

这是我的版本:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

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

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

</xsl:stylesheet>

当应用于输入XML时,它会产生以下输出:

<rootnode>
    <section newattribute="NEW" id="1">
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW" param="p1">
            <inner newattribute="NEW"/>
        </outer>
        <outer newattribute="NEW"/>
        <outer newattribute="NEW" param="p5"/>
    </section>
    <section newattribute="NEW" id="2">
        <outer newattribute="NEW">
            <inner newattribute="NEW" anotherparam="ap1"/>
            <inner newattribute="NEW" param="p4"/>
            <inner newattribute="NEW"/>
        </outer>
    </section>
</rootnode>