Search code examples
javaxmlxsltjava-5

Replace xmlns attribute of root node using xslt


I have xml like below

<rnp xmsns="v1">
  <ele1 line="1">
    <ele2></ele2>
  </ele1>
</rnp>

I want to change it to

<rnp xmsns="v2">
  <ele1 line="1">
    <ele2></ele2>
  </ele1>
</rnp>

using xslt 1.0.

I am using below xsl.

<?xml version="1.0" encoding="iso-8859-1"?>

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns="v2">
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@*|*|node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="rnp">
        <rnp>
            <xsl:apply-templates select="*"/>
        </rnp>
    </xsl:template> 
</xsl:stylesheet>

But this xsl does not copy the attributes so line attribute is not generated in output.

sample output

<?xml version="1.0" encoding="UTF-8"?><rnp xmlns="v2"><ele1>1
        <ele2/>
      </ele1></rnp>

How to change only the text of xmlns attrbiute using xslt? Is there any other way to change xmlns using xslt? I have only option of xslt 1.0.

Thanks.


Solution

  • This transformation:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:param name="pNS" select="'v2'"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="*[true()]">
      <xsl:element name="{local-name()}" namespace="{$pNS}">
           <xsl:apply-templates select="node()|@*"/>
      </xsl:element>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the provided XML document (corrected to make it in the namespace "v1":

    <rnp xmlns="v1">
      <ele1 line="1">
        <ele2></ele2>
      </ele1>
    </rnp>
    

    produces the wanted, correct result:

    <rnp xmlns="v2">
       <ele1 line="1">
          <ele2/>
       </ele1>
    </rnp>
    

    Do note:

    1. The desired new default namespace is passed to the transformation as an external parameter -- thus the smae transformation without any modification can be used in every case when the default namespace must be modified.

    2. This unusual looking template match: <xsl:template match="*[true()]"> makes it possible to avoid the XSLT processors "recoverable ambiguity error" messages if we had coded it just as <xsl:template match="*"> and is shorter and more elegant than specifying a priority.