Create xmlns attribute in the XML using XSLT Transformation

北战南征 提交于 2019-12-06 08:32:56

问题


I am trying to add the xmlns attribute to the resulting XML with a value passed by parameter during XSLT transformation using JDK Transformer (Oracle XML v2 Parser or JAXP) but it always defaults to http://www.w3.org/2000/xmlns/

My source XML

<test/>

My 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>

My Result

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

My Desired Result

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

回答1:


Firstly, in the XSLT data model, you don't want to create an attribute node, you want to create a namespace node.

Namespace nodes are usually created automatically: if you create an element or attribute in a particular namespace, the requisite namespace node (and hence, when serialized, the namespace declaration) are added automatically by the processor.

If you want to create a namespace node that isn't necessary (because it's not used in the name of any element or attribute) then in XSLT 2.0 you can use xsl:namespace. If you're stuck with XSLT 1.0 then there's a workaround, that involves creating an element in the relevant namespace and then copying its namespace node:

<xsl:variable name="ns">
  <xsl:element name="neil:dummy" namespace="{$param}"/>
</xsl:variable>
<process>
  <xsl:copy-of select="$ns/*/namespace::neil"/>
</process>



回答2:


Michael Kay provided you with the correct answer, but based on your comments, you aren't sure how to use it in your transformation.

Here is a complete transformation:

 <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>

When this transformation is applied on the provided XML document:

<test/>

the wanted, correct result is produced:

<process xmlns="http://example.com" xmlns:neil="neilghosh.com" />



回答3:


Namespace declarations in XML are not attributes even though they look like attributes. In XSLT 2.0 you can use <xsl:namespace name="neil" select="$myNameSpace" /> to add a namespace declaration to the result tree dynamically but that feature is not available in XSLT 1.0.




回答4:


Don't try to create "xmlns" attributes yourself. Create the namespaces in the XSLT and they will be done automatically. This XSLT works (tested with 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>

And gives the following output:

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



回答5:


Finally got an workaround which worked with my XSLT Processor (Oracle XML V2 Parser)

I had to transform it to a DOM Document and then persist that DOM to filesystem instead of outputting directly to StreamResult

I used DOMResult in the transform method

Following XSLT fragment worked but there was an extra xmlns:xmlns="http://www.w3.org/2000/xmlns/" which was probably absorbed by Document and did not appear in the final output when I persisted to file system.

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

I know this is not the best way to do but given the parse constraint this is the only choice I have now.



来源:https://stackoverflow.com/questions/12179258/create-xmlns-attribute-in-the-xml-using-xslt-transformation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!