Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with adding xmlns attribute to XML document using XSL

Tags:

xml

xslt

I have the following in my XSL which adds a xmlns to my XML.

<xsl:template match="root">
    <xsl:element name="root" namespace="myXslLoc">
        <xsl:attribute name="Name">Default</xsl:attribute>
        <xsl:apply-templates/>
    </xsl:element>
<xsl:template>

The above does add a xmlns attribute to the root element (the top level element). However it also added a xmlns to the subsequent element. This is how it turned out:

<root Name="Default" xmlns="myXslLoc">
    <steps xmlns="">  <-- where did this attribute come from?
    .
    .
    .
    </steps>
</root>

I have no ideas where that xmlns in the steps element come from. I have no code that specifies the adding of the xmlns to the steps element. Below is a snipet of my xsd:

<xs:complexType name="root">
    <xs:sequence>
        <xs:element name="steps" type="steps" maxOccurs="1" MinOccurs="1"/>
    </xs:sequence>
    <xs:attribute name="Name" type="xs:string" use="required"/>
</xs:complexType>

<xs:complexType name="steps">
    <xs:sequence>
        <xs:element name="step" type="step" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

Is there something wrong in my xsl or xsd? I can not seem to figure out where the problem came from.

Thanks.

EDIT: Following Dimitre's transformation code, I have managed to insert the namespace attribute into the root element. However, more instances of namespace attribute appeared further down in the transformed xml document.

The below is what happened:

<root Name="Default" xmlns="myXslLoc">
    <steps>  <-- where did this attribute come from?
        <step name="A">
        .
        </step>
        .
        .
        <!-- the below is the final steps element -->
        <step name="Z" xmlns="">  <-- this xmlns was unexpectedly added.
            <steps xmlns="myXslLoc"> <-- this one as well.
            .
            .
            .
            </steps>
        </step>
        <step Name="Step manually added by identity transformation (addLastNode stuff)">
        .
        .
        .
        </step>
    </steps>
</root>

The xsl looks something like this:

<xsl:template match="root">
    <xsl:element name="root namespace="myXslLoc">
        <xsl:attribute name="Name">Default</xsl:attribute>
        <xsl:apply-templates/>
    </xsl:element>
<xsl:template>

<xsl:template match="*">
    <xsl:element name="{name()}" namespace="{$addMyXslLoc}">
        <xsl:copy-of select="namespace::*"/>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
<xsl:template>

<xsl:param name="addMyXslLoc" select="'myXslLoc'"/>

<xsl:template match="/*/steps/step[position()=last()]">
    <xsl:call-template name="identity"/>
    <xsl:copy-of select="$addLastNodes"/>
</xsl:template>

<xsl:param name="addLastNodes">
    <step Name="Total Cost">
        <items>
            <item name="A">
            </item>
            <item name="b">
            </item>
        </items>
    </step>
</xsl:param>

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

I liked how the namespace now appears on the root element (along with the Name attribute). But I now face the problem of unable to get rid of the namespaces which was inserted into the last element of the xml document excluding the one that is added via the transformation.

EDIT: Updated the addLastNodes xsl.

like image 263
BeraCim Avatar asked Aug 16 '10 02:08

BeraCim


People also ask

What is xmlns xsl?

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> The xmlns pseudo-attribute maps the shorthand name xsl onto the full namespace for use throughout the document that follows. Thus the stylesheet element above is prefixed with xsl: .

What is XSL attribute?

The <xsl:attribute> element creates an attribute in the output document, using any values that can be accessed from the stylesheet. The element must be defined before any other output document element inside the output document element for which it establishes attribute values.

Does XML use XSL?

XSLT is used to transform XML documents into XHTML documents, or into other XML documents.

What is the purpose of terminate attribute in XSL message?

The terminate attribute gives you the choice to either quit or continue the processing when an error occurs.


2 Answers

@Vincent-Marchetti has already explained what is causing the problem. Here is a complete solution.

This 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:strip-space elements="*"/>

 <xsl:param name="pNamespace" select="'myXslLoc'"/>

  <xsl:param name="addLastNodes">
    <step Name="Total Cost">
        <items>
            <item name="A">
            </item>
            <item name="b">
            </item>
        </items>
    </step>
 </xsl:param>


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

  <xsl:template match="/*/steps/step[position()=last()]">
    <xsl:call-template name="repNamespace"/>
    <xsl:apply-templates select="ext:node-set($addLastNodes)/*"/>
 </xsl:template>

 <xsl:template match="*" name="repNamespace">
  <xsl:element name="{name()}" namespace="{$pNamespace}">
    <xsl:copy-of select="namespace::*"/>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<root>
 <steps>
  <step>1</step>
  <step>2</step>
  <step>3</step>
 </steps>
</root>

produces the wanted, correct result:

<root xmlns="myXslLoc">
   <steps>
      <step>1</step>
      <step>2</step>
      <step>3</step>
      <step Name="Total Cost">
         <items>
            <item name="A"/>
            <item name="b"/>
         </items>
      </step>
   </steps>
</root>
like image 179
Dimitre Novatchev Avatar answered Sep 21 '22 07:09

Dimitre Novatchev


There is nothing wrong with the XSL template; it's just not doing what you want it to do.

What it is doing is creating an element 'root' in the myXslLoc namespace, and then (in the apply-template step) copying the children of the context node (root, in NoNameSpace), in their (the children's) namespace, which is NoNameSpace; so your result is the parent node {myXslLoc}root node, with children {}steps

If what you want is for the steps elements to also be in the myXslLoc root, you need to explicitly create {myXslLoc}steps nodes using xsl:element; just as you did for the 'root' template.

like image 23
Vincent Marchetti Avatar answered Sep 22 '22 07:09

Vincent Marchetti