1
votes

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.

2
Why would you want to use XSLT for this? A simple text replace on the source would do, as this text only exists at one point, right at the start of the document. - Flynn1179
I want to apply some templates and then change the xmlns to new version. Transformation is used as version upgrade. - Jaydeep Patel
Good question, +1. This is definitely a task that is best done with XSLT. Moreover, the new default namespace can be provided as an external parameter to the transformation, making it highly reusable. - Dimitre Novatchev
@Flynn1179 Using textual replacements in text with a syntax like XML is always a bad idea. Whether it's a straightforward replace or using regular expressions, there are too many pitfalls like failing to escape markup characters. XSLT would make sure the result is correctly formatted, there's no unwanted unforseen replacements and all the namespace scopes remain intact in all the right places. What if the namespace is declared in multiple places with different prefixes? - G_H
Well, it does depend on the context, but most text replace mechanisms allow changing only the first (I'm fairly sure Java's does), so you wouldn't suffer these kind of pitfalls. It's certainly a LOT more efficient than processing an entire XML document and generating a new one if this would work. An XSLT-based solution might be more robust, but certainly a lot less efficient. If you were replacing many references throughout a document I'd entirely agree with you, but one piece of text in the root element is a LOT simpler. - Flynn1179

2 Answers

3
votes

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.

0
votes
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns="v2">
    <xsl:output method="xml" indent="yes"/>

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

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

</xsl:stylesheet>

Output:

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