我有以下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
以便将其复制?
答案 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>