Changing namespace for XML file in XSL Translation

13,415

This transformation:

 <xsl:template match="*">
     <xsl:element name="cmp:{name()}" namespace="CompanyURL">
       <xsl:copy-of select="@*"/>
       <xsl:apply-templates/>
     </xsl:element>
 </xsl:template>
 <xsl:template match="/*">
     <cmp:container xmlns:cmp="CompanyURL">
       <xsl:copy-of select="@*"/>
       <xsl:apply-templates/>
     </cmp:container>
 </xsl:template>
</xsl:stylesheet>

when performed on the provided XML document:

<foo xmlns="companyURL">
  <num1>asdf</num1>
  <num2>ghjkl</num2>
</foo>

produces the wanted, correct result:

<cmp:container xmlns:cmp="CompanyURL">
   <cmp:num1>asdf</cmp:num1>
   <cmp:num2>ghjkl</cmp:num2>
</cmp:container>
Share:
13,415
adam_0
Author by

adam_0

Updated on July 20, 2022

Comments

  • adam_0
    adam_0 almost 2 years

    So I have an input file that uses my company's namespace in the default namespace (xmlns="companyURL") but I want my output file to use something other than the default namespace (xmlns:cmp="companyURL"). So I construct my file using the cmp namespace, but then I want to copy some of the inner elements:

    <xsl:element name="cmp:container">
      <xsl:for-each select="foo">
        <xsl:copy-of select="." />
      </xsl:for-each>
    </xsl:element>
    

    Unfortunately, what this does is define the default namespace for each of those inner elements, making the file incredibly verbose and ugly. Simplified example:

    Source:

    <foo xmlns="companyURL">
      <num1>asdf</num1>
      <num2>ghjkl</num2>
    </foo>
    

    Turns into:

    <cmp:container xmlns:cmp="companyURL">
      <num1 xmlns="companyURL">asdf</num1>
      <num2 xmlns="companyURL">ghjkl</num2>
    </cmp:container>
    

    Of course, companyURL is big and long and ugly, and it's the same in both places, so I would prefer the above result to just be the following:

    <cmp:container xmlns:cmp="companyURL">
      <cmp:num1>asdf</cmp:num1>
      <cmp:num2>ghjkl</cmp:num2>
    </cmp:container>
    

    Is there an easy way to do this, or should I convert everything under the cmp namespace to the default namespace? I would prefer to use the explicit namespace naming if possible, it aids in understanding the XSLT in my experience.

  • adam_0
    adam_0 over 13 years
    Why do you have <xsl:copy-of select="@*"/> in your XSLT?
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @adam_0: This copies all attributes of the element. In your concrete example there are no attributes, but if we want to use this code as a general convertor, it must be able to convert correctly all documents -- including such in which there are elements with attributes.
  • adam_0
    adam_0 over 13 years
    My XML Schema specifies that there will be no attributes, so I'm guessing it's fine to leave that line out?
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    If you are 100% sure you can remove it, but leaving it doesn't hurt anything -- simply no attributes will be copied. It is always better to have more generic code. Imagine that tomorrow there is a change in the schema and there would be attributes. Then you'd need to add copying of attributes. In case you used the more generic code from the very start, this change in schema will not affect you at all.
  • adam_0
    adam_0 over 13 years
    Thanks for your help and powerful, concise answers. +1
  • adam_0
    adam_0 over 13 years
    A follow-up I just thought about: could I make this work for any namespace prefix by changing the top template line of <xsl:element name="cmp:{name()}" namespace="CompanyURL"> to <xsl:element name="cmp:{local-name()}" namespace="CompanyURL"> (effectively trimming off any namespace prefix and putting on my own)?
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @adam_0: Yes, this is the way to do prefix-renaming.