2

I have a XML:

<doc>
   <tag1>
      <tag11>1</tag11>
      <tag12>abc</tag12>
      <tag13>test</tag13>
      <tag14>content</tag14>
      <tag15>2-</tag15>
      <tag16>content</tag16>
      <tag17>
         <tag171>TITLE</tag171>
         <tag172>T3</tag172>
         <tag173>No</tag173>
      <tag17>
      <tag18 id="t/9905">aaa</tag18>
      <tag18 id="t/9905">bbb</tag18>
   </tag1>
   <tag2>
      <tag21>2016</tag21>
      <tag22>
         <tag221>1</tag221>
         <tag222>OMG</tag222>
      </tag22>
      <tag23>
         <tag231>Test</tag231>
         <tag232>2016-01-18T00:00:00</tag232>
         <tag233>This is a test</tag233>
      </tag23>
   </tag2>
</doc>

I want to add an attribute (namespace) to the root element: /doc such that the output would look like:

<doc xmlns="urn:test">
   <tag1>
      <tag11>
         <othertags />
      </tag11>
   </tag1>
   <tag2>
      <tag21>
         <othertags2 />
      </tag21>
   </tag2>
</doc>

I've tried three xslt (skipped the default copy all part to reduce length of the question).

xslt1: see below, the problem is that empty namespace xmlns="" is added to all sub-node of /doc (i.e.: /doc/tag1 and /doc/tag2)

<xsl:template match="/doc">
   <xsl:element name="{local-name()}" namespace="urn:test" >
      <xsl:copy-of select="attribute::*"/>
         <xsl:apply-templates select="@*|node()" />
   </xsl:element>
</xsl:template>

Xslt2: see below, the problem is that "ns" is added to root node: and

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

xslt3: see below, the problem is that error reported: Undefined namespace prefix 'urn'. XPST0081: A namespace prefix used in an expression must be expandable into a namespace URI using the statically known namespaces.

<xsl:template match="/*">
   <xsl:copy>
      <xsl:attribute name="xmlns">
         <xsl:value-of select="urn:test" />
      </xsl:attribute>
   <xsl:copy-of select="@*" />
   <xsl:apply-templates />
   </xsl:copy>
</xsl:template> 

I just want a simple output with xmlns="urn:test" with the root node /doc.

Any help would be appreciated!

1 Answer 1

2

I want to add an attribute (namespace) to the root element

A namespace declaration is not an attribute. And the change required here is not to the root element alone: the namespace declared at root is inherited by all its descendants. That means you need to move all elements into the new namespace:

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

<xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="urn:test">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

5 Comments

Michael, Thanks for the answer. The xslt your provided has same output as my first xslt. I really don't want to have the "xmlns=""" on all sub-nodes. Is there a way to remove it on sub-nodes with a 2nd xslt?
@dellair The output of my XSLT does not have "xmlns=""" on all sub-nodes - see: xsltransform.net/pPzifq3
This is absolutely my bad. I just edited the question and had the full xml copied. You can see that "xmlns=""" has been added to sub-nodes with the full xml.
Your new XML is not well-formed. If I correct that, I still don't see any nodes with "xmlns=""" - see: xsltransform.net/pPzifq3/1
Michael, you couldn't be more right. My issue was I used the "/*" in the match pattern instead of "*". Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.