XSLT:向rootnode的所有后代添加属性



我有以下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,这样它就会被复制?

我想给每个节点添加一个新属性,除了根节点。

我认为唯一不希望添加属性的元素是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>

经验教训:

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

我建议你这样做:

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>

如果您添加一个与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>

相关内容

  • 没有找到相关文章

最新更新