Създайте атрибут 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:namespace. Ако сте останали с 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
Това ли е защото oracle.xml.parser.v2.XSLProcessor на моя JDeveloper? Има ли по-добър начин за анализатор 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 Spec го позволява: 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. com) ] myNameSpace - person Neil; 29.08.2012
comment
добре - така че процесът на елемента трябва да бъде в пространството от имена, което идва от параметъра. Ще се опитам да създам елемент вътре в ‹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 версия=2.0 - person Neil; 29.08.2012
comment

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

Трябваше да да го трансформирам в DOM документ и след това да запазя този DOM в файлова система, вместо да извежда директно към StreamResult

Използвах DOMResult в метод на трансформация

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

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

Знам, че това не е най-добрият начин, но като се има предвид ограничението за анализ, това е единственият избор, който имам сега.

person Community    schedule 30.08.2012