4

Hi I am writing an XSLT and within that I am using <xsl:copy-of> function. Now when it's executed then namesapce from xml are also getting copied. In order to remove that I used function like <xsl:copy-of select="$RootNode/Child" copy-namespaces="no"/>. But If Child is having some more child elements then namespaces are appearing in that. So can anyone please tell me how can I remove that. Below is the snippet of my xslt and XML I am using.

<xsl:template match="/">
    <xsl:element name="Parent">
    <xsl:copy-of select="Child" copy-namespaces="no"/>
    </xsl:element>

And XML is:

<Child>
<GrandChild>
 <PhoneNumberType>DayPhone</PhoneNumberType>
</GrandChild></Child>

namespaces are not appearing in CustomerParty but they are present in Child but they are present in GrandChild.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Kapil
  • 832
  • 2
  • 14
  • 29

2 Answers2

10

The copy-namespaces="no" attribute doesn't strip off all namespace nodes -- as noted in the XSLT 2.0 spec:

If it takes the value no, then none of the namespace nodes are copied: however, namespace nodes will still be created in the result tree as required by the namespace fixup process: see 5.7.3 Namespace Fixup. This attribute affects all elements copied by this instruction: both elements selected directly by the select expression, and elements that are descendants of nodes selected by the select expression.

Here is an example how to get rid of all the (non-mandatory) namespace nodes:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match="@*">
  <xsl:attribute name="{local-name()}">
   <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

When this general transformation is applied on this XML document:

<x:nums xmlns:x="my:x">
  <x:num>01</x:num>
  <x:num>02</x:num>
  <x:num>03</x:num>
  <x:num>04</x:num>
  <x:num>05</x:num>
  <x:num>06</x:num>
  <x:num>07</x:num>
  <x:num>08</x:num>
  <x:num>09</x:num>
  <x:num>10</x:num>
</x:nums>

the wanted, correct result is produced:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

Do note:

  1. The transformation is not XSLT-2.0 - specific and can be used with XSLT 1.0, too.

  2. Removing all namespace nodes is generally an unsafe process, because nodes from different namespaces are all put in the "no namespace". In this process some attributes may be lost and the process is generally not reversible (not 1:1).

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • +1 Correct answer. But I think you meant [Reserved Prefixes and Namespace Names](http://www.w3.org/TR/xml-names/#xmlReserved) instead of _"mandatory"_ –  Apr 08 '11 at 16:30
0

With this template you should be able to remove namespaces:

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

Also refer to: http://www.devang-gandhi.net/blog/remove-namespace-attribute-from-xml-root-xslt/

Does this help you with your problem?

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Peter
  • 1,786
  • 4
  • 21
  • 40
  • This snippet doesn't handle attributes that are in a namespace. – Dimitre Novatchev Apr 08 '11 at 13:15
  • @Dimitre: You are right Dimitre. Thank you for your answer. (+1) I just looked at that and realized it. I have only needed this a few times so far and it always worked for me deleting the namespaces from elements only. I added it to my favorites so I remember ;-) – Peter Apr 08 '11 at 13:20