Fixing the problem with XSLT 2.0

Wot, no namespaces?
Image by psd via Flickr

I asked about my XSLT issues on the Gnome XSLT mailing list and got this reply, which neatly summarises where I was going wrong… (though the being ‘shouted at’ part tells you a lot about the dysfunctional aspects of a lot of online software development, but I am used to that by now)

The name of the element is a complex object with a
namespace and a local name.

With <svg width=”1000px” height=”800px” version=”1.1″
xmlns=”http://www.w3.org/2000/svg“>, the element’s name is
{http://www.w3.org/2000/svg}svg.  With <svg width=”1000px”
height=”800px” version=”1.1″>, the element’s name is {}svg.  These are
NOT THE SAME, and XSLT that works to transform one will not transform
the other.  You may as well ask why changing <svg> to <gvs> does not work.

There is a neat answer to this, specifying xpath-default-namespace="http://www.w3.org/2000/svg" in the xsl tag at the start of the stylesheet (I have to lose the non-standard indent attribute too) – giving this:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.w3.org/2000/svg">
<xsl:param name="colour">yellow</xsl:param>
<xsl:template match="/">
	<xsl:apply-templates select="svg"/>
</xsl:template>
<xsl:template match="svg">
	<xsl:copy>
		<xsl:for-each select="@*">
			<xsl:copy/>
		</xsl:for-each>
		<xsl:text>
</xsl:text>
		<xsl:apply-templates select="rect"/>
		<xsl:apply-templates select="line"/>
		<xsl:apply-templates select="text"/>
		<xsl:apply-templates select="circle"/>
	</xsl:copy>
</xsl:template>
<xsl:template match="line">
	<xsl:copy>
		<xsl:for-each select="@*">
			<xsl:copy/>
		</xsl:for-each>
	</xsl:copy>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="rect">
	<xsl:copy>
		<xsl:for-each select="@*">
			<xsl:copy/>
		</xsl:for-each>
	</xsl:copy>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text">
	<xsl:copy>
		<xsl:for-each select="@*|node()">
			<xsl:copy/>
		</xsl:for-each>
	</xsl:copy>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="circle">
	<xsl:if test="@stroke=$colour">
		<xsl:copy>
			<xsl:for-each select="@*">
				<xsl:copy/>
			</xsl:for-each>
		</xsl:copy>
		<xsl:text>
</xsl:text>
	</xsl:if>
</xsl:template>
</xsl:stylesheet>

This is only supported in XSLT 2.0, an accepted standard, but more or less orphaned by the big software houses and, in particular, the browser builders. But help is at hand in the form of the Saxonb XSL processor, so a command line like this:

saxonb-xslt -xsl:pickcolour.xsl -s:memmap.svg -o:test.svg colour=green does the job.

About these ads