Hasif
Hasif

Reputation: 21

How to remove names from the non-empty namespaces they belong to?

I want to transform an input xml file using xslt to change the name of a particular element which can appear at different places of the xml tree.

I have an xml like the following,

 <catalog>
 <cd>
  <ost:title>Empire Burlesque</ost:title>
  <artist>Bob Dylan</artist>
  <country>USA</country>
  <company>
     <ost:name>Columbia<ost:name>
  </company>
  <price>10.90</price>
  <year>1985</year>
 </cd>
</catalog>

I want to remove all the 'ost:' prefix from all the elements and keep everything else as it is using xslt. An example code will be appreciated.

Upvotes: 2

Views: 293

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243529

This transformation is most general. It removes all elements and attributes from namespaces that are specified within a global parameter. It also removes all namespace nodes that are one of those namespaces:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:delNs>
   <ns>some:namespace1</ns>
   <ns>some:namespace3</ns>
 </my:delNs>

 <xsl:variable name="vdelNS"
  select="document('')/*/my:delNs/*"/>

 <xsl:template match="*">
  <xsl:element name="{name()}" namespace="{namespace-uri()}">
   <xsl:copy-of select="namespace::*[not(.=$vdelNS)]"/>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:copy-of select="."/>
 </xsl:template>

 <xsl:template priority="10" match=
 "*[namespace-uri()=document('')/*/my:delNs/*]">

  <xsl:element name="{local-name()}">
   <xsl:copy-of select="namespace::*[not(.=$vdelNS)]"/>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match=
 "@*[namespace-uri()=document('')/*/my:delNs/*]">
   <xsl:attribute name="{local-name()}">
    <xsl:value-of select="."/>
   </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the following XML document (based on the provided, but corrected to be well-formed and extended to contain 3 namespaces and elements and attributes in them):

 <catalog xmlns:ost="some:namespace1"
  xmlns:x="some:namespace2"
  xmlns:y="some:namespace3">
 <cd>
  <ost:title>Empire Burlesque</ost:title>
  <y:artist>Bob Dylan</y:artist>
  <country>USA</country>
  <company ost:type="big">
     <ost:name>Columbia</ost:name>
  </company>
  <x:price>10.90</x:price>
  <year>1985</year>
 </cd>
</catalog>

the wanted result is produced:

<catalog xmlns:x="some:namespace2">
   <cd>
      <title>Empire Burlesque</title>
      <artist>Bob Dylan</artist>
      <country>USA</country>
      <company type="big">
         <name>Columbia</name>
      </company>
      <x:price>10.90</x:price>
      <year>1985</year>
   </cd>
</catalog>

Explanation:

  1. The first two templates are almost equivalent to the identity rule, but they do not copy namespace nodes for the namespaces specified in <my:delNs>.

  2. The last two templates are for all elements and attributes that belong to a namespace listed under <my:delNs>. Only in these two templates names are actually changed to only local names.

Upvotes: 0

Jukka Matilainen
Jukka Matilainen

Reputation: 10198

In your example, you don't seem to have other namespaces than the one you want to remove. So, here is an example of an XSLT stylesheet, which removes all namespaces from elements (not just your ost:).

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- identity template: copy everything as is... -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- ... except for elements, 
       create a similarly named element without a namespace -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

It uses the identity transformation to copy everything as-is, but overrides that for elements to create an element with the same local name, but no namespace.

If you want to just remove your ost: namespace, you can include the namespace declaration for that namespace, and change the latter template to match ost:*.

Upvotes: 2

Related Questions