替换输入xml中的命名空间

时间:2012-08-13 02:10:01

标签: xslt namespaces xslt-1.0

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

的Sample1

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

样品2

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

我已经编写了以下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>

1 个答案:

答案 0 :(得分:0)

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

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

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

更新

我刚刚注意到Dimitre解决了一个非常相似的问题here