Enigma
Enigma

Reputation: 315

Remove namespaces for all except for one node

Given the following source xml:

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns="http://someorg.org">
    <text>
        <status value="generated"/>
        <div xmlns="http://www.w3.org/1999/xhtml">
            <p>Some text</p>
            <p>Some text</p>
        </div>
    </text>
</Test>

I would like to have the same output as the above source xml (the source xml contains many other xml nodes but for this section, I want to output it as it is, with no changes.) I have the following xslt (see below) which strips the elements of their namespaces as desired. Unfortunately, it also strips the div elements of their name spaces but I want to retain them. The closest I got to achieving my aim is the following xslt but it outputs the div element twice because of the apply-templates but I only want the div element once with its namespace.

This is my xslt:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://someorg.org"
xmlns="http://someorg.org"
exclude-result-prefixes="f xsl">

    <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:template match="/">

        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match = "f:text/f:status">
    <status value ="generated"/>

            <div xmlns="http://www.w3.org/1999/xhtml">
                <xsl:apply-templates/>
            </div>
    </xsl:template>     
</xsl:stylesheet>

Upvotes: 0

Views: 380

Answers (2)

Tim C
Tim C

Reputation: 70648

Instead of trying to remove namespaces for all elements (as handled by your <xsl:template match="*"> template, you can only target elements in the "http://someorg.org" namespace. Simply change the template match to this

<xsl:template match="f:*">

For the elements in the "http://www.w3.org/1999/xhtml" namespace, you could use the identity template to pick up everything else

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://someorg.org">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

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

Upvotes: 3

Stefan Hegny
Stefan Hegny

Reputation: 2187

add a template

<xsl:template match="*[local-name()='div' 
 and namespace-uri() = 'http://www.w3.org/1999/xhtml']">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

to perform a copy instead of creating a namespace-stripped element.

Upvotes: 0

Related Questions