3

这是我的输入 XML 文档:

<test xmlns="http://www.example.com/v1">
  <qnameValue xmlns:foo="http://foo.example.com/">foo:bar</qnameValue>
</test>

我想使用 XSLT (2.0) 将本文档的命名空间更改为 v2,即所需的输出为:

<test xmlns="http://www.example.com/v2">
  <qnameValue xmlns:foo="http://foo.example.com/">foo:bar</qnameValue>
</test>

我正在尝试使用此样式表:

<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
     xmlns:previous='http://www.example.com/v1'>
  <xsl:output encoding='UTF-8' indent='yes' method='xml'/>
  <!-- Identity transform -->
  <xsl:template match='@*|node()'>
    <xsl:copy>
      <xsl:apply-templates select='@*|node()'/>
    </xsl:copy>
  </xsl:template>
  <!-- Previous namespace -> current. No other changes required. -->
  <xsl:template match='previous:*'>
    <xsl:element name='{local-name()}' namespace='http://www.example.com/v2'>
      <xsl:apply-templates select='@* | node()' />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

不幸的是,输出结果如下:

<test xmlns="http://www.example.com/v2">
  <qnameValue>foo:bar</qnameValue>
</test>

即 qnameValue 上的关键名称空间绑定已经消失。有没有办法强制将所有命名空间绑定的副本复制到输出?

4

1 回答 1

5

应该这样做,并且与 XSLT 1.0 兼容:

<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
     xmlns:previous='http://www.example.com/v1'>
  <xsl:output encoding='UTF-8' indent='yes' method='xml'/>
  <!-- Identity transform -->
  <xsl:template match='@*|node()'>
    <xsl:copy>
      <xsl:apply-templates select='@*|node()'/>
    </xsl:copy>
  </xsl:template>
  <!-- Previous namespace -> current. No other changes required. -->
  <xsl:template match='previous:*'>
    <xsl:element name='{local-name()}' namespace='http://www.example.com/v2'>
      <xsl:copy-of select='namespace::*[not(. = namespace-uri(current()))]' />
      <xsl:apply-templates select='@* | node()' />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

在您的示例输入上运行时,结果是:

<test xmlns="http://www.example.com/v2">
  <qnameValue xmlns:foo="http://foo.example.com/">foo:bar</qnameValue>
</test>

这是一种类似的方法,通过将旧 uri 存储在一个变量中并从那里访问它,可能会更有效一些:

<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
     xmlns:previous='http://www.example.com/v1'>
  <xsl:output encoding='UTF-8' indent='yes' method='xml'/>
  <xsl:variable name='oldUri' select='namespace-uri((//previous:*)[1])' />

  <!-- Identity transform -->
  <xsl:template match='@*|node()'>
    <xsl:copy>
      <xsl:apply-templates select='@*|node()'/>
    </xsl:copy>
  </xsl:template>
  <!-- Previous namespace -> current. No other changes required. -->
  <xsl:template match='previous:*'>
    <xsl:element name='{local-name()}' namespace='http://www.example.com/v2'>
      <xsl:copy-of select='namespace::*[not(. = $oldUri)]' />
      <xsl:apply-templates select='@* | node()' />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
于 2013-04-22T15:18:55.283 回答