XSLT 2.0 - 更改名称空间而不丢弃现有的前缀绑定

Dav*_*rth 3 xml xslt xml-namespaces xslt-2.0

这是我的输入XML文档:

<test xmlns="http://www.example.com/v1">
  <qnameValue xmlns:foo="http://foo.example.com/">foo:bar</qnameValue>
</test>
Run Code Online (Sandbox Code Playgroud)

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

<test xmlns="http://www.example.com/v2">
  <qnameValue xmlns:foo="http://foo.example.com/">foo:bar</qnameValue>
</test>
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

不幸的是输出结果如下:

<test xmlns="http://www.example.com/v2">
  <qnameValue>foo:bar</qnameValue>
</test>
Run Code Online (Sandbox Code Playgroud)

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

JLR*_*she 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>
Run Code Online (Sandbox Code Playgroud)

在样本输入上运行时,结果为:

<test xmlns="http://www.example.com/v2">
  <qnameValue xmlns:foo="http://foo.example.com/">foo:bar</qnameValue>
</test>
Run Code Online (Sandbox Code Playgroud)

这是一种类似的方法,通过将旧的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>
Run Code Online (Sandbox Code Playgroud)