0

名前空間プレフィックス付きとプレフィックスなしの 2 種類の入力 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>

名前空間を「 http://testlibrary」から「http ://newlibrary 」に変更する XSLT を書きましたが、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>
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 に答える