Создайте атрибут xmlns в XML с помощью преобразования XSLT

Я пытаюсь добавить атрибут xmlns к результирующему XML со значением, переданным параметром во время преобразования XSLT с использованием JDK Transformer (Oracle XML v2 Parser или JAXP), но по умолчанию он всегда имеет значение http://www.w3.org/2000/xmlns/

Мой исходный XML

<test/>

Мой XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://example.com">
    <xsl:param name="myNameSpace" select="'http://neilghosh.com'"/>
    <xsl:template match="/">
        <process>
            <xsl:attribute name="xmlns:neil">
                <xsl:value-of select="$myNameSpace"/>
            </xsl:attribute>
        </process>
    </xsl:template>
</xsl:stylesheet>

Мой результат

<?xml version="1.0"?>
<process xmlns="http://www.w3.org/2000/xmlns/" xmlns:neil="neilghosh.com">
</process>

Мой желаемый результат

<?xml version="1.0"?>
<process xmlns="http://example.com"  xmlns:neil="neilghosh.com">
</process>

person Neil    schedule 29.08.2012    source источник
comment
Вы должны использовать действительный URI для пространства имен, например http://example.com/, а не http://example.com. Браузеры исправят последнее на первое, если вы введете их в адресную строку, но это исправит очевидную ошибку при вводе. У вас не может быть HTTP URI без части пути.   -  person Jon Hanna    schedule 29.08.2012


Ответы (5)


Во-первых, в модели данных XSLT вы не хотите создавать узел атрибута, вы хотите создать узел пространства имен.

Узлы пространства имен обычно создаются автоматически: если вы создаете элемент или атрибут в определенном пространстве имен, требуемый узел пространства имен (и, следовательно, при сериализации, объявление пространства имен) автоматически добавляется процессором.

Если вы хотите создать узел пространства имен, в котором нет необходимости (потому что он не используется в имени какого-либо элемента или атрибута), тогда в XSLT 2.0 вы можете использовать пространство имен xsl :. Если вы застряли с XSLT 1.0, есть обходной путь, который включает в себя создание элемента в соответствующем пространстве имен и последующее копирование его узла пространства имен:

<xsl:variable name="ns">
  <xsl:element name="neil:dummy" namespace="{$param}"/>
</xsl:variable>
<process>
  <xsl:copy-of select="$ns/*/namespace::neil"/>
</process>
person Michael Kay    schedule 29.08.2012
comment
Работает ли это, когда переменная $ns содержит RTF, а не набор узлов? Я ожидал, что для его преобразования сначала понадобится вызов exslt:node-set() или что-то подобное. - person Ian Roberts; 29.08.2012
comment
Спасибо, что следующий код в шаблоне не работал ‹xsl: variable name = ns› ‹xsl: element name = neil: dummy namespace = {$ myNameSpace} /› ‹/ xsl: variable› ‹process› ‹xsl: copy-of select = $ ns / * / namespace :: neil / ›‹/process› Можете ли вы отредактировать свое решение так, чтобы он соответствовал точному XSLT, который мне нужно написать для этого вопроса? - person Neil; 29.08.2012
comment
@NeilGhosh, Может вы слышали о функции расширения xxx:node-set()? - person Dimitre Novatchev; 29.08.2012
comment
Да, думаю, ему нужен xx: node-set (). Извините, я только указываю людям в правильном направлении, я не беру их за руки и не провожу по ним - особенно когда это связано с XSLT 1.0, потому что это всегда очень неприятное путешествие. - person Michael Kay; 30.08.2012

Майкл Кей дал вам правильный ответ, но, судя по вашим комментариям, вы не знаете, как использовать его в своей трансформации.

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

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pNamespace" select="'neilghosh.com'"/>

 <xsl:variable name="vDummy">
   <xsl:element name="neil:x" namespace="{$pNamespace}"/>
 </xsl:variable>

 <xsl:template match="/*">
  <xsl:element name="process" namespace="http://example.com">
    <xsl:copy-of select="namespace::*"/>
    <xsl:copy-of select="ext:node-set($vDummy)/*/namespace::*[.=$pNamespace]"/>
  </xsl:element>
 </xsl:template>
 </xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу:

<test/>

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

<process xmlns="http://example.com" xmlns:neil="neilghosh.com" />
person Dimitre Novatchev    schedule 29.08.2012
comment
Спасибо за ответ. Я получаю следующую ошибку a.xsl ‹Строка 11, столбец 41›: XML-23049: (Ошибка) FOTY0021: недопустимый тип узла - person Neil; 29.08.2012
comment
Это потому, что мой JDeveloper oracle.xml.parser.v2.XSLProcessor? Есть ли лучший способ парсера v2? - person Neil; 29.08.2012
comment
Удалена библиотека парсера Oracle v2 и запущен приведенный выше код, но результат был ‹ns0: process xmlns: ns0 = example.com xmlns : neil = neilghosh.com / › - person Neil; 29.08.2012
comment
@NeilGhosh, я запускал это со всеми 9 процессорами XSLT, с которыми я работаю - все они производят результат, который я скопировал и вставил в этот ответ. Можете ли вы использовать MSXML, .NET XslCompiledTransform, Saxon, XQSharp или AltovaXML (XML-SPY)? - person Dimitre Novatchev; 29.08.2012
comment
Я не уверен, могу ли я использовать приведенные выше синтаксические разборы в своем коде. Я запустил тот же код в NetBeans, и он также без надобности дал префикс ns0 - person Neil; 29.08.2012
comment
@NeilGhosh, это невозможно контролировать. Спецификация W3 допускает это: процессоры XSLT могут использовать префикс QName, указанный в атрибуте name, при выборе префикса, используемого для вывода созданного элемента как XML; однако они не обязаны этого делать. - person Dimitre Novatchev; 30.08.2012
comment
Благодарность ! Мне нужно использовать oracle.xml.parser.v2.XSLProcessor. Попытка выяснить, можно ли избежать ошибки XML-23049. - person Neil; 30.08.2012
comment
Спасибо, у меня решение сработало. В моем случае я использовал просто <xsl:copy-of select="ext:node-set($vDummy)/*/namespace::*" /> без дополнительных параметров $pNamespace voodo. - person dma_k; 03.12.2014
comment
Могу я задать вопрос: как можно скопировать пространства имен из элемента <xsl:stylesheet>? Например. как использовать текущую таблицу стилей в качестве набора узлов? Что-то вроде current()/ancestor::xsl:stylesheet, но заставить его работать не удалось ... - person dma_k; 03.12.2014
comment
@dma_k: выбирается document-node() (/) текущего модуля таблицы стилей, используя это выражение XPath: document('') - person Dimitre Novatchev; 03.12.2014

Объявления пространств имен в XML не являются атрибутами, даже если они выглядят как атрибуты. В XSLT 2.0 вы можете использовать <xsl:namespace name="neil" select="$myNameSpace" /> для динамического добавления объявления пространства имен в результирующее дерево, но эта функция недоступна в XSLT 1.0.

person Ian Roberts    schedule 29.08.2012
comment
Я добавил ‹xsl: element name = process namespace = {$ myNameSpace}› ‹xsl: namespace name = neil select = $ myNameSpace /› ‹/ xsl: element› под шаблоном, но он по-прежнему дает мне вывод ‹process xmlns = neilghosh.com - person Neil; 29.08.2012

Не пытайтесь самостоятельно создавать атрибуты xmlns. Создайте пространства имен в XSLT, и они будут выполнены автоматически. Этот XSLT работает (протестирован с Saxon 9.4):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:neil="neilghosh.com"    
xpath-default-namespace="http://example.com"
xmlns="http://example.com" version="2.0">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="myDynamicNamespace" select="'http://neilghosh.com'"/>

<xsl:template match="/">
    <xsl:element name="process">   
        <xsl:namespace name="neil" select="$myDynamicNamespace"/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

И дает следующий результат:

<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://example.com" xmlns:neil="http://neilghosh.com"/>
person FiveO    schedule 29.08.2012
comment
Весь смысл вопроса в том, что значение xmlns должно поступать из параметра [отправленного transformer.setParameter (myNameSpace, example. ru)] myNameSpace - person Neil; 29.08.2012
comment
ok - значит, процесс элемента должен находиться в пространстве имен, которое исходит из параметра. Я попытаюсь создать элемент внутри ‹process›, который имеет пространство имен из параметра ... - person FiveO; 29.08.2012
comment
‹Xsl: template match = /› ‹xsl: element name = process namespace = {$ myNameSpace}› ‹/ xsl: element› ‹/ xsl: template› - person FiveO; 29.08.2012
comment
Мне нужно, чтобы это было в корневом теге процесса - person Neil; 29.08.2012
comment
xsl: namespace не работал даже жестко ‹xsl: stylesheet version = 2.0 - person Neil; 29.08.2012
comment
позвольте нам продолжить обсуждение в чате - person Neil; 29.08.2012

Наконец-то получил обходной путь, который работал с моим XSLT-процессором (Oracle XML V2 Parser)

Мне пришлось преобразовать его в документ DOM, а затем сохранить этот DOM в файловая система вместо вывода непосредственно в StreamResult

Я использовал DOMResult в метод преобразования

Следующий фрагмент XSLT работал, но был дополнительный xmlns: xmlns = "http://www.w3.org/2000/xmlns/", который, вероятно, был поглощен Document и не отображался в окончательном выводе, когда я сохранял файловую систему.

 <process>    
      <xsl:attribute name="xmlns">
        <xsl:value-of select="'http://example.com'"/>
      </xsl:attribute> 
 <process>

Я знаю, что это не лучший способ сделать это, но с учетом ограничений синтаксического анализа это единственный выбор, который у меня сейчас есть.

person Community    schedule 30.08.2012