XML to SVG with XSLT part I

In pursuit of useful applications of SVG, I've become interested in using XSL transforms to turn data stored as XML into an SVG representation. I found a good starting article at A List Apart and it pointed to a great reference by Paul Grosso and Norman Walsh. These might be dated now, but I found them helpful starting points.

On to my example. We're going to need some data. I had a look at StatsCan and found a report on population by sex and age group. I would have liked to get some more complete raw data, but it appears to cost a few bucks, so I'll make do. I believe there are ways to scrape the data out of the table with just XSLT, but since this is a learning experience for me, I decided to skip that step by just pulling the numbers out by hand and creating an XML file with a text editor.
The results of my effort look a little like this:

<?xml version="1.0" encoding='UTF-8'?>
<populationbyageandsex>
<recordbyagegroup>
<agegroup>0-4</agegroup>
<kpersons>1695.9</kpersons>
<kmalepersons>868.0</kmalepersons>
<kfemalepersons>827.9</kfemalepersons>
</recordbyagegroup>
...
<recordbyagegroup>
<agegroup>90 and over</agegroup>
<kpersons>162.7</kpersons>
<kmalepersons>42.6</kmalepersons>
<kfemalepersons>120.1</kfemalepersons>
</recordbyagegroup>
</populationbyageandsex>

The root node is called "populationbyageandsex" and each record (or row of data) is kept in a "recordbyagegroup". Between the open and close tags for "recordbyagegroup" are the fields for that record. Each field has a unique name and the content (between the open and close tags) of the element is the value of the field. The format is something I just made up for this example, XML is nice that way.

The next step was to write the XSL transformations that would understand the data well enough to create a chart in SVG.

At first I didn't understand that XSLT is a complete programming language (it may not have been at points in the past, but that's what it is now). I also didn't realize that XSLT is designed for transforming one flavour of XML to another. I guess I was just pretty confused by the whole thing (that's not to say that I'm not still a little muddy on the subject).

Here's what the XSLT looks like now that it works:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml"
omit-xml-declaration = "no"
indent="yes"
version="1.0"
doctype-system = "-//W3C//DTD SVG 1.0//EN"
doctype-public = "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
/>

<xsl:template match="/populationbyageandsex">
<svg viewBox="0 0 3000 2000" xmlns:svg="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:apply-templates select="recordbyagegroup"/>
</svg>
</xsl:template>

<xsl:template match="recordbyagegroup">
<xsl:call-template name="plot-line">
<xsl:with-param name="length" select="kpersons"/>
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="label" select="agegroup"/>
</xsl:call-template>
</xsl:template>

<!-- length is the length of the bar for this data value -->
<!-- position is ordinal value of this data point in the data set -->
<!-- label is the text used to describe the data set -->
<xsl:template name="plot-line">
<xsl:param name="label"/>
<xsl:param name="length"/>
<xsl:param name="position"/>
<xsl:element name = "polyline" >
<xsl:attribute name="points"> 10,<xsl:value-of select="$position * 100"/>,<xsl:value-of select="$length"/>,<xsl:value-of select="$position * 100"/> </xsl:attribute>
<xsl:attribute name="fill"> none </xsl:attribute>
<xsl:attribute name="stroke"> black </xsl:attribute>
<xsl:attribute name="stroke-width"> 30 </xsl:attribute>
</xsl:element>
<xsl:element name = "text" >
<xsl:attribute name="x"> <xsl:value-of select="$length + 10"/> </xsl:attribute>
<xsl:attribute name="y"> <xsl:value-of select="$position * 100 + 20"/> </xsl:attribute>
<xsl:attribute name="font-size"> 40 </xsl:attribute>
<xsl:attribute name="stroke"> red </xsl:attribute>
<xsl:attribute name="stroke-width"> 1 </xsl:attribute>
<xsl:value-of select="$label"/>
</xsl:element>

</xsl:template>

</xsl:stylesheet>

Look at the template called "plot-line" in the code. A template in XSLT seems to work a whole lot like a function in other programming languages. It's called using the xsl:call-template element and the parameters are each passed in a xsl:with-param tag. The named parameters show up in the template using xsl:param elements.

The xsl:value-of element does all the substitution in my example (there may be other and better ways, but I don't know them yet). The select attribute of the value-of tag can refer to several expressions. A tag in the current node like the places that use select="kpersons". A function from XPath like select="position()" (this gets the ordinal of the current node in a collection). A formula like select="$position * 100". Note that I did a bad thing here - I named a parameter "position" and I filled its value from the position() function. I realize this can be a little confusing, I'll fix it later. In the formula case, $position refers to the parameter position from the xsl:param name="position" line.

The plot-line template produces one line of the chart and a text label for it. It does this with the xsl:element tag. This tag inserts an element into the output. The attributes of the element are nested with xsl:attribute tags. There's not really too much more to it once you know that, but I'll go over some more details later. Oh, here's the SVG - you'll need an SVG viewer to display it.

Can't view SVG? There's an explanation of how to view SVG on SVGBasics.com.

4
Your rating: None Average: 4 (1 vote)

There's an XPath2/XSLT2 version of the tutorial now too, which I hope will be equally useful as folks move to the new technologies.

Hi there! Thanks for the pointer, I take it you mean the slides from your presentation at Extreme Markup Languages in Montréal. I think I prefer your older tutorial only because of my background. Once I have a better grasp of XML, I expect I'll get more out of your newer tutorial. Thanks for taking the time to come read.
Nice pictures from Las Vegas btw (the Red Rocks Canyon is my favourite).

[...] I&#8217;ve been thinking of doing something like this for awhile: render my web statistics in on-the-fly SVG graphs via some XSLT. Rob did something like this way back when he first started his blog. I know Mint has the powerful &#8220;Fresh View&#8221; pepper that uses SVG to display its data visually. Andrew Gregory has had his home-brewed solution for a little while now. But this one just came up in Technorati, it includes the 3 small files you need to tweak. Fun &#8220;milk carton&#8221; WordPress template, too. [...]

Its possible to simplify this a bit, e.g, by replacing the whole

though I'm not sure about your syntax there, shouldn't that be

style="font-size: 40pt; stroke:red; stroke-width: 1"

?

Shaun, you're right. I could have written something a lot shorter there. You can put the text element in with all its attributes and the XSLT parser will just copy it over. (This is one of my first XSLT experiments and I didn't know that then)