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.

Advertisements

Using XSLT to manipulate an SVG file


I am generating a lot of the graphics for my project using Scalable Vector Graphics (SVG) – an XML format.

The advantages of SVG are obvious – it is human readable, it preserves some of the data in the output (eg in the relative placing of the dots on a graph), Groovy has good support for it and, in theory at least XML Stylesheet Transformations (XSLT) means that it can be manipulated outside of a formal programming environment using another bit of XML (an XSL stylesheet) and freely available XSLT tools – eg xsltproc on Linux.

But XSLT is one of those Cinderellas of the computing world – widely relied on but not generally understood or widely discussed. As a result I have struggled over the last 24 hours to work out how to do what ought to be a simple thing: removing a set of dots of one colour from an SVG. I still have not got to the bottom of all the issues – specifically xltproc seems to have an issue with XML namespace declarations and/or DTD declarations – but I have fixed it for all practical purposes, so thought I should document it for future users…

Before I describe the problem more fully as well as the solution, I have to recommend this book – XSLT: Mastering XML Transformations. For Beginners and Advanced Users – which gave me the pointers to a solution I just could not find online.

So here is the graph (in PNG format because WordPress does not support SVG) I want to manipulate.

Firefox memory mapThis is memory map – via Valgrind – of Firefox (7) opening and closing (I created a page that, once Firefox was configured, would close the browser.)

The different types of memory accesses – for instructions (red), loads (blue), stores (yellow) and modifies (green) are all on superimposed and which colour you see depends on the order they are written if they access the same page.

So the answer, with an SVG, is obvious, just look at the colour you want to see.

Ought to be easy, right? Well, I suppose when you know how to do it, it is easy. But it’s not completely simple!

Each dot on the graph is drawn with an XML element like this:

<circle cx='102' cy='699' r='1' fill='none' stroke='red' stroke-width='1' />

The trick is to create a template for all the elements but inside that template only copy out the elements that match the correct stroke attribute. (Attributes are not children of node elements either, so you have to copy them out explicitly.)

Here’s a stylesheet that does it:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" indent="yes"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<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 code be shortened to just copy-of the line, rect and text elements.)

And here’s an example:

xsltproc  -o inst.svg --stringparam colour "red" pickcolour.xsl master.svg

Instructions executed by Firefox 7

O’Reilly free ebook on HTML 5


HTML5 MMW Desktop

Must be worth a download if you are wondering what HTML 5 is all about – go here.

You have to register but I can assure you it is free – as I have a copy and did not enter any credit card details.

“What is HTML5?” is about 10 pages long – so a read on your next commute?

XPath tool


An illustration of XSL transformation and form...
Image via Wikipedia

This is a helpful XPath tool if you are looking to sharpen your skills.

You can test your XPath expressions online, and even load your own file to check against.

XSLT conundrum solved


I had a moment of epiphany today about my XSLT problem – the answer is not to seek to append stuff to the end of the document, but to get the template right in the first place eg:

<xsl:template match=”/dataroot”>
<html>
<body>
<h2>Report</h2>
<div title=”Summaries”>
<xsl:apply-templates select=”Headlines” />
</div>
<div title=”Fulltext”>
<xsl:apply-templates select=”Headlines/Headline” /></div>
</body>
</html>
</xsl:template>
<xsl:template match=”Headlines”>
<h4><xsl:value-of select=”Headline” /></h4>
<br /><xsl:value-of select=”Summary” /><br />
<br /><a>
<xsl:attribute name=”href”>#
<xsl:value-of select=”Headline” />
</xsl:attribute>
Full Text
</a>
<br /><br />
</xsl:template>
<xsl:template match=”Headline”>
<br /><br /><a>
<xsl:attribute name=”name”>
<xsl:value-of select=”.” />
</xsl:attribute>
</a>
<xsl:value-of select=”../FullText” />
</xsl:template>
</xsl:stylesheet>

How can I do this in XSLT?


Diagram of the basic elements and processing f...
Image via Wikipedia

I have a very simple (single relation) database, of news stories that I export to xml, so I get something like this:

<?xml?>
<headline>
<top>This is a story </top>
<summary>Some summary of the story</summary>
<full_text>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pharetra sagittis risus a ultrices. In a lectus eu nunc scelerisque gravida ac elementum felis. Phasellus. </full_text>
</headline>

And so on….

What I want to do is use an XSL stylesheet to convert this into some HTML where the top line is printed, then the summary and then a link to the full text, which is at the bottom of the document.

Writing the XSL that will extract the top line and the summary is easy, but how can I get a link to what is, in effect, some appended text at the end of the document? Is it even possible?

I have a huge and authoritative tome on XSLT  – XSLT: Mastering XML Transformations. For Beginners and Advanced Users – which I will now consult, but anyone know before I delve in?