Preventing random namespace tags in xsl output
When doing xsl transformations to output xhtml in some processors namespace attributes can appear on random elements. This makes the resulting code much larger than necessary but also prevents the page from being validated. To prevent these kinds of problems here’s the simple solution.
The problem
When outputting xhtml using a xsl transformation (depending on the parser used) it can happen that xmlns attributes are added to random elements. This not only increases your code in size (depending on the amount of namespaces declared, it can sometimes double in size) but also prevents the page from being validated by the W3 html validator.
Because of the nature of xhtml (it's an xml file) namespace atrributes are allowed on all elements but i like to keep my code clean and readable. An example of how code may turn out, looks something like this (code generated using MS XML 4.0)
...
<p xmlns="http://www.w3.org/1999/xhtml"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
<a href="/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="">Home</a>
</p>
...
That's an amazing amount of code for just a simple paragraph and a hyperlink.
The solution
Luckily the solution to this problem is pretty easy and can be solved using the 'exclude-result-prefixes' attribute. This attribute must be placed on the <xsl:stylesheet/> element, which is the root element for every xsl stylesheet. For every namespace you don't wan't to appear in the resulting xhtml file add the namespace prefix to this attribute. For the example above this looks something like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="xi ms dt xsi">
...
With this solution these namespace attributes should no longer be in the generated code. Unfortunately the exclude-result-prefixes attribute doesn't apply to code being generated using copy or copy-of. In my situation I copy small fragments of XHTML from my source document and these still contain the unwanted namespace attributes.
<!-- Copy XHTML fragments to output-->
<xsl:template match="@*|node()" mode="xhtml">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="xhtml"/>
</xsl:copy>
</xsl:template>
The only way around this problem is to use templates to parse the entire xml document. Lucikly these can be very genric and kan be used in all kinds of situations. Below is an example of some templates of code which
<xsl:template match="xhtml-snippet">
<xsl:apply-templates mode="xhtml"/>
</xsl:template>
<xsl:template match="*" mode="xhtml">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@*|node()|comment()" mode="xhtml"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*" mode="xhtml">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="text()" mode="xhtml">
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="comment()" mode="xhtml">
<xsl:comment>
<xsl:value-of select="." />
</xsl:comment>
</xsl:template>