Xslt 替换输入xml中的命名空间

Xslt 替换输入xml中的命名空间,xslt,namespaces,xslt-1.0,Xslt,Namespaces,Xslt 1.0,我有两种类型的输入xml,一种带有名称空间前缀,另一种没有前缀,我想替换名称空间 样本1 <v1:Library xmlns:v1="http://testlibrary" xmlns:v2="http://commonprice"> <v1:Books_details> <v1:Name>test1</v1:Name> <v1:title>test2</v1:title> <v2:price xmlns="http:

我有两种类型的输入xml,一种带有名称空间前缀,另一种没有前缀,我想替换名称空间

样本1

<v1:Library xmlns:v1="http://testlibrary" xmlns:v2="http://commonprice">
<v1:Books_details>
<v1:Name>test1</v1:Name>
<v1:title>test2</v1:title>
<v2:price xmlns="http://commonprice">12</v2:price>
</v1:Books_details>
</v1:Library>

测试1
测试2
12
样本2

<Library xmlns="http://testlibrary">
<Books_details>
<Name>test1</Name>
<title>test2</title>
<price xmlns="http://commonprice">12</price>
</Books_details>
</Library>

测试1
测试2
12
我编写了以下XSLT来将名称空间从“http://testlibrary“到”http://newlibrary“它对sample1很好,但对sample2不起作用。它给出了错误的结果。它还可以更改price元素的名称空间,即使它没有要替换的名称空间

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:param name="old_namespace"/>
    <xsl:param name="new_namespace"/>
    <xsl:template match="/">
    <xsl:apply-templates select="@* | node()"/>
    </xsl:template>

    <xsl:template match="text() | comment() | processing-instruction()">
        <xsl:copy>
            <xsl:apply-templates select="text() | comment() | processing-instruction()"/>
        </xsl:copy>
    </xsl:template>
    <!--  Template used to copy elements  -->   
    <xsl:template match="*">

         <xsl:variable name="name">
            <xsl:choose>
                <xsl:when test="contains(name(), ':')">
                    <xsl:value-of select="name()"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="local-name()"/>
                </xsl:otherwise>
            </xsl:choose> 
         </xsl:variable>

        <xsl:element name="{$name}" namespace="{$new_namespace}">
             <!-- Copy all namespace through except for namespace to be changed --> 
             <xsl:for-each select="namespace::*">
                 <xsl:if test="string(.)!=$old_namespace">
                     <xsl:copy-of select="."/>
                 </xsl:if>
            </xsl:for-each> 
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

注意:我的第一个答案是错误的,因为在XSLT1.0中,不能在匹配模式中使用变量引用

此样式表将Sample1或Sample2作为输入文档,并用新名称空间替换元素名称中所有出现的旧名称空间。注意:您可以更改xsl:param的xsl:variable

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

<xsl:variable name="old_namespace" select="'http://testlibrary'" />
<xsl:variable name="new_namespace" select="'http://newlibrary'" />

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

  <xsl:template match="*">
    <xsl:choose>    
      <xsl:when test="namespace-uri()=$old_namespace">
       <xsl:element name="{local-name()}" namespace="{$new_namespace}">
        <xsl:apply-templates select="@*|node()"/>
       </xsl:element>
      </xsl:when>
      <xsl:otherwise>    
       <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
       </xsl:copy>
      </xsl:otherwise>    
    </xsl:choose>    
  </xsl:template>

</xsl:stylesheet>

警告 上面的样式表只会更改元素的名称空间。它不会更改属性的名称空间,也不会删除无关的名称空间节点

关于更具体的解决方案 对于变量名称空间上的操作,需要通用解决方案是非常罕见的。名称空间,因为它们是固定的和已知的。仔细考虑一下,如果你真的需要一个通用的解决方案。如果您需要一个特定的解决方案,这意味着替换特定名称空间的出现,那么事情就会变得容易得多,例如使用此样式表

<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:old="http://testlibrary"
      xmlns:new="http://newlibrary">

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

<xsl:template match="old:*">
  <xsl:element name="{local-name()}" namespace="http://newlibrary">
    <xsl:apply-templates select="@*|node()" />
  </xsl:element>
</xsl:template>

</xsl:stylesheet>


更新 我刚刚注意到了一个非常相似的问题的答案