Замените атрибут xmlns корневого узла с помощью xslt

У меня есть xml, как показано ниже

<rnp xmsns="v1">
  <ele1 line="1">
    <ele2></ele2>
  </ele1>
</rnp>

Я хочу изменить его на

<rnp xmsns="v2">
  <ele1 line="1">
    <ele2></ele2>
  </ele1>
</rnp>

с помощью xslt 1.0.

Я использую ниже xsl.

<?xml version="1.0" encoding="iso-8859-1"?>

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns="v2">
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@*|*|node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="rnp">
        <rnp>
            <xsl:apply-templates select="*"/>
        </rnp>
    </xsl:template> 
</xsl:stylesheet>

Но этот xsl не копирует атрибуты, поэтому атрибут строки не создается на выходе.

образец вывода

<?xml version="1.0" encoding="UTF-8"?><rnp xmlns="v2"><ele1>1
        <ele2/>
      </ele1></rnp>

Как изменить только текст атрибута xmlns с помощью xslt? Есть ли другой способ изменить xmlns с помощью xslt? У меня есть только вариант xslt 1.0.

Спасибо.


person Jaydeep Patel    schedule 07.11.2011    source источник
comment
Почему вы хотите использовать XSLT для этого? Подойдет простая замена текста в источнике, так как этот текст существует только в одном месте, прямо в начале документа.   -  person Flynn1179    schedule 07.11.2011
comment
Я хочу применить некоторые шаблоны, а затем изменить xmlns на новую версию. Трансформация используется как обновление версии.   -  person Jaydeep Patel    schedule 07.11.2011
comment
Хороший вопрос, +1. Это определенно задача, которую лучше всего решать с помощью XSLT. Кроме того, новое пространство имен по умолчанию может быть предоставлено как внешний параметр преобразования, что делает его многократно используемым.   -  person Dimitre Novatchev    schedule 07.11.2011
comment
@Flynn1179 Flynn1179 Использование текстовых замен в тексте с таким синтаксисом, как XML, всегда является плохой идеей. Будь то простая замена или использование регулярных выражений, существует слишком много ловушек, таких как отсутствие экранирования символов разметки. XSLT обеспечит правильное форматирование результата, отсутствие нежелательных непредвиденных замен и сохранение всех областей пространства имен во всех нужных местах. Что, если пространство имен объявлено в нескольких местах с разными префиксами?   -  person G_H    schedule 07.11.2011
comment
Что ж, это зависит от контекста, но большинство механизмов замены текста позволяют изменить только первый (я уверен, что это делает Java), поэтому вы не столкнетесь с такими ловушками. Это, безусловно, НАМНОГО эффективнее, чем обработка всего XML-документа и создание нового, если это сработает. Решение на основе XSLT может быть более надежным, но, безусловно, гораздо менее эффективным. Если бы вы заменяли много ссылок в документе, я бы с вами полностью согласился, но один фрагмент текста в корневом элементе НАМНОГО проще.   -  person Flynn1179    schedule 07.11.2011
comment
Сказав это, учитывая, что изменение пространства имен является лишь частью того, что должен делать код XSLT, любое универсальное решение, которое просто меняет пространство имен и оставляет нетронутым содержание документа, будет бесполезным, независимо от того, XSLT ли это. или на основе замены строки.   -  person Flynn1179    schedule 07.11.2011
comment
Обратите внимание, что в мире XSLT объявление пространства имен НЕ является атрибутом; если вы попытаетесь манипулировать им как атрибутом, вы потерпите неудачу. Скорее, это своего рода директива, которая изменяет имя (в данном случае) каждого элемента в документе. Таким образом, вы не можете просто изменить значение одного атрибута, вы должны изменить имя каждого элемента. Это ключ к пониманию решения Дмитрия.   -  person Michael Kay    schedule 07.11.2011


Ответы (2)


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

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pNS" select="'v2'"/>

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

 <xsl:template match="*[true()]">
  <xsl:element name="{local-name()}" namespace="{$pNS}">
       <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу (исправлено, чтобы сделать его в пространстве имен "v1":

<rnp xmlns="v1">
  <ele1 line="1">
    <ele2></ele2>
  </ele1>
</rnp>

выдает желаемый правильный результат:

<rnp xmlns="v2">
   <ele1 line="1">
      <ele2/>
   </ele1>
</rnp>

Обратите внимание:

  1. Требуемое новое пространство имен по умолчанию передается преобразованию в качестве внешнего параметра — таким образом, преобразование smae без каких-либо изменений может использоваться в каждом случае, когда необходимо изменить пространство имен по умолчанию.

  2. Это необычно выглядящее совпадение с шаблоном: <xsl:template match="*[true()]"> позволяет избежать сообщений XSLT-процессоров об «исправимой ошибке неоднозначности», если бы мы закодировали его так же, как <xsl:template match="*">, и оно короче и элегантнее, чем указание приоритета.

person Dimitre Novatchev    schedule 07.11.2011
comment
Я получаю этот вывод: ‹ns0:rnp xmlns:ns0=v2› ‹ns1:ele1 xmlns:ns1=v2 line=1› ‹ns2:ele2 xmlns:ns2=v2/› ‹/ns1:ele1› ‹/ns0: rnp› все элементы имеют префикс квалификатора пространства имен. - person Jaydeep Patel; 07.11.2011
comment
Я использую процессор xslt по умолчанию, который поставляется с java 1.5. - person Jaydeep Patel; 07.11.2011
comment
@Jaydeep: я проверил с помощью 5 различных процессоров XSLT, что результат, указанный в моем ответе, получен: MSXML3, MSXML4, .NET XslCompiledTransform, AltovaXML, Saxon 6.5.4, XML-SPY для XSLT 2.0. Скорее всего, это ошибка вашего процессора XSLT, хотя вывод, который он производит, эквивалентен моему выводу (без учета лексических различий, которые производят деревья, и их узлы одинаковы). Я думаю, что спецификация XSLT допускает некоторую свободу в сериализации, так что это может даже не быть ошибкой. Возможно, @_Michael Kay лучше всех объяснит. - person Dimitre Novatchev; 07.11.2011

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

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

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

</xsl:stylesheet>

Выход:

<rnp xmlns="v2">
    <ele1 line="1">
        <ele2 />
    </ele1>
</rnp>
person Kirill Polishchuk    schedule 07.11.2011