在您的示例中选择命名空间前缀似乎没有任何明确的逻辑,所以我认为这很难实现,但这里是如何做类似的事情:
<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>