我有以下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>