使用XSLT,我想美化我的XML并提取命名空间声明并改为使用前缀。
我得到了:
<a xmlns="ns1">
<b xmlns="ns2">
<c xmlns="ns3"/>
</b>
</a>
我想:
<a xmlns="ns1" xmlns:b="ns2" xmlns:c="ns3">
<b:b>
<c:c/>
</b:b>
</a>
自动执行此操作将很困难。所以我考虑了多个步骤。每个命名空间一个。
我尝试使用namespace="{namespace-uri(.)}"
,但我无法将命名空间拉到根元素。
答案 0 :(得分:3)
在您的示例中,您选择的名称空间前缀似乎没有任何明确的逻辑,所以我认为这很难实现,但这里是如何做类似的事情:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common"
exclude-result-prefixes="exslt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kNs" match="*[namespace-uri()]" use="namespace-uri()" />
<!-- Build a list of elements to represent all namespaces -->
<xsl:variable name="uniqueNsNf">
<xsl:for-each select="//*[generate-id() =
generate-id(key('kNs', namespace-uri())[1])]">
<xsl:element name="ns{position()}:ns" namespace="{namespace-uri()}" />
</xsl:for-each>
</xsl:variable>
<xsl:variable name="uniqueNs" select="exslt:node-set($uniqueNsNf)/*" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[namespace-uri()]">
<xsl:variable name="nsMap"
select="$uniqueNs[namespace-uri() =
namespace-uri(current())]" />
<xsl:element name="{substring-before(name($nsMap), ':')}:{local-name()}"
namespace="{namespace-uri()}">
<xsl:copy-of select="$uniqueNs/namespace::*"/>
<xsl:apply-templates select="@* | node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
当在以下输入上运行时:
<a xmlns="ns1">
<b xmlns="ns2">
<c xmlns="ns3"/>
<b xmlns="ns2" />
</b>
<d xmlns="otherNs">
<b xmlns="ns3" />
</d>
</a>
结果是:
<ns1:a xmlns:ns1="ns1" xmlns:ns2="ns2" xmlns:ns3="ns3" xmlns:ns4="otherNs">
<ns2:b>
<ns3:c />
<ns2:b />
</ns2:b>
<ns4:d>
<ns3:b />
</ns4:d>
</ns1:a>