XSLT for SVG generation
Dave Pawson has anglicised some great XSLT work from Jakub Vojtíšek and provided Relax NG schemas and other improvments. These stylesheets convert from an XML graph specification to SVG. These would be very useful in XML database work where the graph data is generated on the fly.
I loaded Dave's versions of the spreadsheets and some of the examples in his article into eXist.. There are scripts to graph one or multi-dimensional data and XY plots. eXist has a transform module which allows a XSLT stylesheet to be applied to a selected XML node. Parameters are limited to string values, so the stylesheet template cannot be passed the graph definition. The supplied scripts include a linking stylesheet but I could not get the xsl:include to work on eXist (1.4) (relative or absolute URI's). This probably my fault rather than a bug, so I had to merge the two to get a working XSLT script.
Here is a simple XQuery script to transform a stored example, choosing the appropriate stylesheet to use:
declare namespace gr = "http://graph2svg.googlecode.com"; declare option exist:serialize "method=xml media-type=image/svg+xml"; let $example := request:get-parameter("example",()) let $graph := doc(concat("/db/Wiki/graph2svg/",$example))/* let $ss := typeswitch ($graph) case element(gr:osgr) return doc("/db/Wiki/graph2svg/xosgr2svg.xsl") case element(gr:msgr) return doc("/db/Wiki/graph2svg/xmsgr2svg.xsl") case element(gr:xygr) return doc("/db/Wiki/graph2svg/xxygr2svg.xsl") default return () return transform:transform ($graph,$ss,())
OSGR - One Series Graph: Pie Charts, Bar charts, Line Charts - XSLT RNG
A Bar chart: graph spec svg
A Pie Chart: graph spec svg
MSGR - Multiple Series Graph: Bar Charts, Box charts.. XSLT RNG
A Multi-line charts: graph specsvg
A Box char: graph spec svg
Two curves: graph spec svg
SVG in XHTML
I really want to generate the SVG on the fly and include in an HTML document. After much wasted time re-learning that the media-type has to be application/xhtml+xml, this script embeds the generated chart, in a suitably sized area:
declare namespace gr = "http://graph2svg.googlecode.com"; declare option exist:serialize "method=xhtml media-type=application/xhtml+xml omit-xml-declaration=no indent=yes doctype-public=-//W3C//DTD XHTML 1.0 Strict//EN doctype-system=http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; let $example := request:get-parameter("example",()) let $graph := doc(concat("/db/Wiki/graph2svg/",$example))/* let $ss := typeswitch ($graph) case element(gr:osgr) return doc("/db/Wiki/graph2svg/xosgr2svg.xsl") case element(gr:msgr) return doc("/db/Wiki/graph2svg/xmsgr2svg.xsl") case element(gr:xygr) return doc("/db/Wiki/graph2svg/xxygr2svg.xsl") default return () let $svg := transform:transform ($graph,$ss,()) return <html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xml:lang="en"> <head> <title>SVG embedded inline in XHTML</title> </head> <body> <h1> SVG embedded inline in XHTML : {$example}</h1> <svg:svg width="500px" height="400px"> {$svg} </svg:svg> </body> </html>
A Pie Chart: svg
Generating SVG Graphs
The data on fires in the UK, gathered by converting an Excel spreadsheet (discussed in a previous item) could be transformed to an XML graph spec and hence to SVG embedded in HTML. Here is the code:
declare namespace d= "http://www.cems.uwe.ac.uk/xmlwiki/data" ; declare option exist:serialize "method=xhtml media-type=application/xhtml+xml omit-xml-declaration=no indent=yes doctype-public=-//W3C//DTD XHTML 1.0 Strict//EN doctype-system=http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; let $fires := doc("/db/Wiki/Convert/fires.xml")//d:fires let $graph := <msgr xmlns="http://graph2svg.googlecode.com" pointType="circle" colorScheme="cold"> <title>Fires in UK</title> <names> {for $year in (2001 to 2008) for $qtr in (1 to 4) return <name>{concat("'",substring(xs:string($year),3,2),"/",$qtr)}</name> } </names> {for $category in ("dwellings", "otherBuildings","vehicles") return <values> <title>{$category}</title> { for $year in (2001 to 2008) for $qtr in (1 to 4) for $value in $fires[@year=$year][@qtr=$qtr][@category=$category] return <value>{string($value)}</value> } </values> } </msgr> return <html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg"> <head> <title>Fires in the UK</title> </head> <body> <h1>Fires in the UK</h1> source {transform:transform( $graph, doc("/db/Wiki/graph2svg/xmsgr2svg.xsl") ,() )} </body> </html>
This script is running from a cached XML file, but we can do it on the fly directly from the Excel file by changing the source of the data to call the conversion script:
let $fires := doc("http://www.cems.uwe.ac.uk/xmlwiki/Convert/fires-ns.xq")//d:fires
This looks like a good case for using an XProc pipeline instead of these ad-hoc connections.
Thanks Dave for bringing Jakub's work to my attention.