XSLT节点副本后跟名称空间更改

时间:2015-08-18 13:56:29

标签: xml xslt

我正在使用XSLT将传入的Web服务调用从旧版本转换为新版本的XML。在此版本更改中,它意味着将元素从父项复制到特定位置的多个子项,并更改定义Web服务版本的XML的名称空间。

我差不多了,但我无法让复制的节点更改为新的命名空间。

旧XML:

<n:request xmlns:n="mynamespace2">
   <n:element>
      <n:id>
         <!-- ... -->
      </n:id>
      <n:source>
         <n:aaa><!-- ... --></n:aaa>
         <n:copyme>
            <n:something attr="value"/>
         </n:copyme>
         <n:bbb><!-- ... --></n:bbb>
         <!-- ... -->
      </n:source>
      <n:ccc/>
      <n:target x="1">
         <n:ddd>text</n:ddd>
         <n:eee>text</n:eee>
         <n:fff><!-- ... --></n:fff>
         <!-- many nodes -->
      </n:target>
      <n:target x="2">
         <n:ddd>text</n:ddd>
         <n:eee>text</n:eee>
         <n:fff><!-- ... --></n:fff>
         <!-- many nodes -->
      </n:target>
   </n:element>
</n:request>

我需要在copyme之后将target及其所有子项复制到每个eee,然后将其从原始位置移除。

我的XSLT:

<xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:myns2="mynamespace2"
        xmlns:myns3="mynamespace3"
        version="1.0">

    <xsl:param name="myns2Param">mynamespace2</xsl:param>
    <xsl:param name="myns3Param">mynamespace3</xsl:param>

    <!-- identity -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- copy the desired node to each child -->
    <xsl:template match="/myns2:request/myns2:element/myns2:target">
        <xsl:element name="{local-name()}" namespace="{$myns3Param}">
            <xsl:apply-templates select="@*|myns2:ddd|myns2:eee" />
            <xsl:copy-of select="../myns2:source/myns2:copyme" />
            <xsl:apply-templates select="node()[not(self::myns2:ddd or self::myns2:eee)]" />
        </xsl:element>
    </xsl:template>

    <!-- remove original node -->
    <xsl:template match="/myns2:request/myns2:element/myns2:source/myns2:copyme" />

    <!-- change namespace -->
    <xsl:template match="@myns2:*">
        <xsl:attribute name="{local-name()}" namespace="{$myns3Param}">
            <xsl:value-of select="." />
        </xsl:attribute>
    </xsl:template>
    <xsl:template match="myns2:*">
        <xsl:element name="{local-name()}" namespace="{$myns3Param}">
            <xsl:apply-templates select="node()|@*" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

实际上,这是输出:

<request xmlns="mynamespace3">
   <element>
      <id>
         <!-- ... -->
      </id>
      <source>
         <aaa><!-- ... --></aaa>
         <bbb><!-- ... --></bbb>
         <!-- ... -->
      </source>
      <ccc/>
      <target x="1">
         <ddd>text</ddd>
         <eee>text</eee>
         <n:copyme xmlns:n="mynamespace2" xmlns:ns1="mynamespace2">
            <n:something attr="value"/>
         </n:copyme>
         <fff><!-- ... --></fff>
         <!-- many nodes -->
      </target>
      <target x="2">
         <ddd>text</ddd>
         <eee>text</eee>
         <n:copyme xmlns:n="mynamespace2" xmlns:ns1="mynamespace2">
            <n:something attr="value"/>
         </n:copyme>
         <fff><!-- ... --></fff>
         <!-- many nodes -->
      </target>
   </element>
</request>

这几乎是正确的,但原始的namespace2仍然存在于复制的元素中。我找了一种方法解决这个问题,但没有任何效果。我该如何修复这个命名空间?

XSLT实施:Saxon-HE 9.5.0.2

1 个答案:

答案 0 :(得分:2)

由于您使用的是XSLT 2.0,因此可以使用<xsl:copy-of select="..." copy-namespaces="no"/>

这将摆脱冗余的命名空间。如果您确实需要将元素移动到不同的命名空间,则不能使用xsl:copy-of并且应该执行显式递归下降,以复制元素和属性,但不复制命名空间(example here)。