我有一个包含许多未使用的命名空间的xml,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com" xmlns:ns3="http://www.c.com" xmlns:ns4="http://www.d.com">
<ns1:Body>
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
我想删除未使用的命名空间,而不必在xslt中指定要删除/维护的命名空间。结果xml应为:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com">
<ns1:Body>
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
我已经google了很多,但还没有找到解决这个问题的方法。有没有?
感谢。
PS:不是100%肯定,但我认为它应该适用于XSL 1.0。
答案 0 :(得分:19)
与@ Martin-Honnen的答案不同,此解决方案可以产生完全理想的结果 - 必要的命名空间节点保留在它们所在的位置并且不会向下移动。
此外,此解决方案正确处理命名空间中的属性:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" priority="-2">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:variable name="vtheElem" select="."/>
<xsl:for-each select="namespace::*">
<xsl:variable name="vPrefix" select="name()"/>
<xsl:if test=
"$vtheElem/descendant::*
[(namespace-uri()=current()
and
substring-before(name(),':') = $vPrefix)
or
@*[substring-before(name(),':') = $vPrefix]
]
">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
将此转换应用于以下XML文档(提供的带有添加的命名空间属性的XML文档):
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com" xmlns:ns3="http://www.c.com" xmlns:ns4="http://www.d.com">
<ns1:Body ns2:x="1">
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
产生了所需的正确结果:
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com">
<ns1:Body ns2:x="1">
<ns2:a>
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
答案 1 :(得分:3)
好吧,如果你使用
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@* | text() | comment() | processing-instruction()">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
然后删除未使用的命名空间,但结果更像是
<ns1:Envelope xmlns:ns1="http://www.a.com">
<ns1:Body>
<ns2:a xmlns:ns2="http://www.b.com">
<ns2:b>data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>
比你要求的要多。
答案 2 :(得分:1)
添加到Dimitre的答案中,如果应保留仅在属性值中出现的名称空间,请添加以下条件:@*[contains(.,concat($vPrefix,':'))]
:
<xsl:if test= "$vtheElem/descendant::* [namespace-uri() = current() and
substring-before(name(),':') = $vPrefix or
@*[substring-before(name(),':') = $vPrefix] or
@*[contains(.,concat($vPrefix,':'))]
]">
由于ns3
,这将正确保留名称空间attrib="ns3:Header"
,如下例所示。
<ns1:Envelope xmlns:ns1="http://www.a.com" xmlns:ns2="http://www.b.com" xmlns:ns3="http://www.c.com" xmlns:ns4="http://www.d.com">
<ns1:Body ns2:x="1">
<ns2:a>
<ns2:b atrib="ns3:Header">data1</ns2:b>
<ns2:c>data2</ns2:c>
</ns2:a>
</ns1:Body>
</ns1:Envelope>