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://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。它给出了错误的结果。即使没有要替换的命名空间,它也会更改价格元素的命名空间。

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

1 回答 1

0

注意:我的第一个答案是错误的,因为在 XSLT 1.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>

更新

我刚刚注意到Dimitre对这里的一个非常相似的问题的解决方案。

于 2012-08-13T09:52:05.153 回答