使用XSLT将XML名称空间转换为顶级前缀

时间:2013-04-26 09:54:41

标签: xml xslt namespaces

使用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(.)}",但我无法将命名空间拉到根元素。

1 个答案:

答案 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>