Removing Extraneous Namespace Declarations - By Force

Posted by bob Fri, 20 Oct 2006 01:35:00 GMT

In developing XML->XML transformations (XSLT 1.x), I've frequently experienced unnecessary ancestor namespace declarations propagating to child elements of the output tree (in Saxon, and Xalan too, I believe). The ultimate consumer of the resultant XML document usually wouldn't care; I just viewed it as annoying behavior...highly annoying, but not a show stopping problem.

The exclude-result-prefixes attribute placed at the root of a stylesheet never seems to perform as advertised, that is - exclude the namespace declarations for the following space separated list of prefixes (the value of the attribute). It is working as it should...but only for literal result elements. Literal result elements, by the way, are elements explicitly placed in the XSLT module to be written to the output (e.g using <myelement> vs. <xsl:element>). There is a decent example here, with a nice comment from Michael Kay.

So, when using <xsl:copy> and <xsl:copy-of>, the processor is going to output any ancestor namespace declarations of the input document it feels it should copy (more detailed explanation of why this is the case is out there, but I'm not going to touch for now).

For various reasons, let's say you really, really wanted to prevent the extraneous namespace declarations when transforming a particular XML document.

A template matching node() and two separate templates matching attributes and text() function as a modified version of the traditional identity template. The node() template creates entirely new elements using <xsl:element>, with an explicit namespace setting of the context node's namespace URI. Thus, the newly created element will be free of any propagated namespace declarations from ancestors.

The template matching/copying only attributes is separate, as the behavior/output of the node() template should not be triggered for attributes.

The template matching text() is separate for the same reason, and requires a priority to override the selection between node() and text() templates when a text node is encountered.

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

<xsl:template match="@*">
   <xsl:copy/>
</xsl:template>

<xsl:template match="text()" priority="1">
   <xsl:value-of select="."/>
</xsl:template>

On a slightly related note, here is a classic Michael Kay mailing list response.

Trackbacks

Use the following link to trackback from your own site:
http://ossolab.com/trackbacks?article_id=removing-extraneous-namespace-declarations-by-force&day=19&month=10&year=2006

Comments

Leave a comment

Comments