Замена нескольких пространств имен на XSLT в корневом элементе - PullRequest
2 голосов
/ 17 января 2012

У меня есть следующий XML-документ

<a:rootElement xmlns:a="http://a/1" xmlns:b="http://b/1" xmlns:c="http://c/1">
 <child1 type="b:type"/>
 <child2 type="c:type"/>
</a:rootElement>

Теперь я хочу изменить URI пространств имен, чтобы получить следующий результат

<a:rootElement xmlns:a="http://a/2" xmlns:b="http://b/2" xmlns:c="http://c/2">
 <child1 type="b:type"/>
 <child2 type="c:type"/>
</a:rootElement>

Больше ничего не должно измениться.Я попытался сделать это с помощью следующей таблицы стилей.

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:a="http://a/2"
xmlns:b="http://b/2"
xmlns:c="http://c/2" >

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

<xsl:template match="/*">
    <xsl:element name="{name()}" namespace="{namespace-uri()}">
        <xsl:copy-of select="document('')/*/namespace::*[name()='a']"/>
        <xsl:copy-of select="document('')/*/namespace::*[name()='b']"/>
        <xsl:copy-of select="document('')/*/namespace::*[name()='c']"/>
        <xsl:copy-of select="node()|@*"/>
    </xsl:element>
</xsl:template>

Я получил следующий неправильный вывод.

<a_0:rootElement xmlns:a_0="http://a/1" xmlns:a="http://a/2" xmlns:b="http://b/2" xmlns:c="http://c/2">
 <child1 type="b:type" xmlns:a="http://a/1" xmlns:b="http://b/1" xmlns:c="http://c/1"/>
 <child2 type="c:type" xmlns:a="http://a/1" xmlns:b="http://b/1" xmlns:c="http://c/1"/>
</a_0:rootElement>

Я также попробовал несколько других способов, но также без нужного вывода.Можно ли вообще изменить пространства имен с помощью XSLT?

Спасибо за любой совет

Ответы [ 2 ]

1 голос
/ 17 января 2012

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:a1="http://a/1"
 xmlns:b1="http://b/1"
 xmlns:c1="http://c/1"
 xmlns:a="http://a/2"
 xmlns:b="http://b/2"
 xmlns:c="http://c/2"
>
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vDoc" select="document('')/*"/>

 <xsl:variable name="vnsA" select="$vDoc/namespace::*[name()='a1']"/>
 <xsl:variable name="vnsB" select="$vDoc/namespace::*[name()='b1']"/>
 <xsl:variable name="vnsC" select="$vDoc/namespace::*[name()='c1']"/>
 <xsl:variable name="vnsA2" select="$vDoc/namespace::*[name()='a']"/>
 <xsl:variable name="vnsB2" select="$vDoc/namespace::*[name()='b']"/>
 <xsl:variable name="vnsC2" select="$vDoc/namespace::*[name()='c']"/>

 <xsl:template match="*">
   <xsl:variable name="vNS" select="namespace-uri()"/>

     <xsl:variable name="vnewNS">
         <xsl:choose>
          <xsl:when test="$vNS = $vnsA">
           <xsl:value-of select="$vnsA2"/>
          </xsl:when>
          <xsl:when test="$vNS = $vnsB">
           <xsl:value-of select="$vnsB2"/>
          </xsl:when>
          <xsl:when test="$vNS = $vnsC">
           <xsl:value-of select="$vnsC2"/>
          </xsl:when>
         </xsl:choose>
     </xsl:variable>

     <xsl:element name="{name()}" namespace="{$vnewNS}">
      <xsl:copy-of select=
      "namespace::*[not(contains('|a|b|c|', concat('|', name(), '|')))]
      "/>
      <xsl:copy-of select="namespace::*[name() = 'a' and not(. = $vnsA)]"/>
      <xsl:copy-of select="namespace::*[name() = 'b' and not(. = $vnsB)]"/>
      <xsl:copy-of select="namespace::*[name() = 'c' and not(. = $vnsC)]"/>

      <xsl:if test="namespace::*[name() = 'a' and . = $vnsA]">
       <xsl:copy-of select="$vnsA2"/>
      </xsl:if>
      <xsl:if test="namespace::*[name() = 'b' and . = $vnsB]">
       <xsl:copy-of select="$vnsB2"/>
      </xsl:if>
      <xsl:if test="namespace::*[name() = 'c' and . = $vnsC]">
       <xsl:copy-of select="$vnsC2"/>
      </xsl:if>

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

</xsl:stylesheet>

при применении к предоставленному документу XML :

<a:rootElement
 xmlns:a="http://a/1"
 xmlns:b="http://b/1"
 xmlns:c="http://c/1">

    <child1 type="b:type"/>
    <child2 type="c:type"/>
</a:rootElement>

создает искомое, правильный результат :

<a:rootElement xmlns:a="http://a/2" xmlns:b="http://b/2" xmlns:c="http://c/2">
   <child1 type="b:type"/>
   <child2 type="c:type"/>
</a:rootElement>
0 голосов
/ 17 января 2012

Я думаю, что Димитр адекватно подтвердил мою точку зрения, что любое решение XSLT будет намного сложнее, чем простая замена текста в первой строке вашего XML-документа перед обработкой его с помощью XSLT.

Элементыиз разных пространств имен это технически совершенно разные элементы.Поскольку технология XML рассматривает их как разные, вам на самом деле приходится обрабатывать и обрабатывать каждый из них, даже если они будут выглядеть одинаково при выводе.

То, как вы это сделаете, зависит от используемой вами платформы, нопростое «найти первое вхождение http://a/1 и заменить его на http://a/2 должно выполнить работу для каждого пространства имен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...