XSLT to generate SVG tutorial: Difference between revisions

The educational technology and digital learning wiki
Jump to navigation Jump to search
mNo edit summary
m (Text replacement - "<pageby nominor="false" comments="false"/>" to "<!-- <pageby nominor="false" comments="false"/> -->")
 
(40 intermediate revisions by the same user not shown)
Line 1: Line 1:
<pageby nominor="false" comments="false"/>
<!-- <pageby nominor="false" comments="false"/> -->
{{web technology tutorial|beginner}}
{{web technology tutorial|intermediate}}
{{under construction}}
{{incomplete}}


== Introduction ==
== Introduction ==
Line 21: Line 21:
* HTML and CSS (some)
* HTML and CSS (some)
* [[XSLT Tutorial - Basics]]
* [[XSLT Tutorial - Basics]]
* [[XPath tutorial - basics]]
* [[Static SVG tutorial]] ('''important''')
* [[Static SVG tutorial]] ('''important''')
* [[Using SVG with HTML5 tutorial]]
* [[SVG/SMIL animation tutorial]] (''optional'')
* [[SVG/SMIL animation tutorial]] (''optional'')


Line 84: Line 86:
</source>
</source>


Now let us examine the template that deals with ''thing''. Since we do not use a template for the root /''/''), we firstly must generate the svg tag.
Now let us examine the template that deals with ''thing''. We don't need a template for the root element (''/''). In the code above, the xsl template for ''thing'' will generate the top-level SVG tag.
<source lang="XML">
<source lang="XML">
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
Line 91: Line 93:
</source>
</source>


Next, we simply have to define an SVG rectangle and substitute the values for width and height by the values that we extract from the XML.
Next, we simply have to define an SVG rectangle and define the SVG attribute values for ''width'' and ''height'' with the values that we extract from the XML. In other words,
''{width}'' and ''{height}'' will be substituted by text found within &lt;width&gt; and &lt;height&gt; tags in the XML document.
''{width}'' and ''{height}'' will be substituted by text found within &lt;width&gt; and &lt;height&gt; tags in the XML document.
 
<source lang="XML">
<rect x="10" y="10" width="{width}" height="{height}" fill="red" stroke="black"/> 
</source>
Live Code (may include slight variations):
Live Code (may include slight variations):
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/zero.xml zero.xml]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/zero.xml zero.xml]
Line 142: Line 146:
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/zero-html5.xsl zero-html5.xsl]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/zero-html5.xsl zero-html5.xsl]


=== Introductory SVG example ===
=== Visualizing some numbers ===
 
The following example ([http://tecfa.unige.ch/guides/svg/ex/html5-xslt/one-html5.xml look at it]) shows how to substitute a number by a bar that appears in elements of the list.
 
In the XML below, we would like to render the contents of the ''age'' element in a more interesting way:
<source lang="XML">
<?xml version="1.0"?>
<?xml-stylesheet href="one-html5.xsl" type="text/xsl"?>
<project>
<title>Simple XML to SVG demo</title>
<people>
  <person>
    <FirstName>Kaspar</FirstName>
    <age>50</age>
    <description>A small man with a green tie</description>
  </person>
  <person>
    <FirstName>Jonathan</FirstName>
    <age>9</age>
    <description>A young person</description>
  </person>
  <person>
  <FirstName>Julie</FirstName>
  <age>30</age>
  <description>A young woman</description>
  </person>
</people>
</project>
 
</source>
 
The XSLT uses fairly simple "rule-based" XSLT programming. The only template of interest concerns the ''age'' element. In addition, we add some more CSS styling to the HTML elements, e.g. div boxes with borders and we also will let the SVG top-level element float to the right.
 
Firstly, we store the value of the (current) element (i.e. the contents) of age in a variable called ''years''. This is not necessary here, but allows simplifying complex XPath expressions. Note that a variable is used in an XPath expression with a $ sign in front, e.g. $years.
<source lang="XML">
<xsl:variable name="years" select="."/>
</source>
The SVG part then looks like this. Note how the ''rect'' height is computed as age*1.2
<source lang="XML">
  <svg style="background-color:yellow;float:right" width="20" height="100"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg">
    <rect x="5px" y="5px" height="{$years*1.2}" width="10px" fill="green" />
  </svg>
</source>
 
Below is the full XSLT code:
<source lang="XML">
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/1999/xhtml"
  >
 
<xsl:output
    method="xml"
    doctype-system="about:legacy-compat"
    omit-xml-declaration = "yes"
    encoding="UTF-8"
    indent="yes" />
 
<xsl:strip-space elements="tasks participants"/>
 
<xsl:template match="/">
  <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta charset="utf-8"></meta>
      <title>XHTML5 + SVG example</title>
    </head>
    <body>
      <p>XHTML5 contents below are generated from XML with XSLT.
      Contents of and age elements are display in both text and with SVG as a green bar.
      Look at the source of this page for the XML and at the <a
      href="http://tecfa.unige.ch/guides/svg/ex/html5-xslt/one-html5.xsl">one-html5.xsl</a>
      file. Read the <a href="http://edutechwiki.unige.ch/en/XSLT_to_generate_SVG_tutorial">
      XSLT to generate SVG tutorial</a></p>
      <hr/>
      <xsl:apply-templates/>
    </body>
</html>
</xsl:template>
 
<xsl:template match="people">
  <h1>People</h1>
  <xsl:apply-templates/>
</xsl:template>
 
<xsl:template match="person">
  <div style="border-style:dotted;margin:10px;padding:5px;width:200px;height:100px;">
    <xsl:apply-templates/>
  </div>
</xsl:template>
 
<xsl:template match="FirstName">
  <xsl:apply-templates/>,
</xsl:template>
 
<xsl:template match="age">
  Age: <xsl:apply-templates/>
  <xsl:variable name="years" select="."/>
  <svg style="background-color:yellow;float:right" width="20" height="100"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg">
    <rect x="5px" y="5px" height="{$years*1.2}" width="10px" fill="green" />
  </svg>
</xsl:template>
 
<xsl:template match="description">
  <p><xsl:apply-templates/></p>
</xsl:template>
 
<xsl:template match="title">
  <h1><xsl:apply-templates/></h1>
</xsl:template>
 
</xsl:stylesheet>
 
</source>
 
Source files:
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/one-html5.xml one-html5.xml]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/one-html5.xsl one-html5.xsl]
 
A more complex example is shown further down in the section [[#Creating_simple_cards_from_tabular_information_structures| Creating simple cards from tabular information structures]]
 
=== Creating a simple bar chart ===


The example we introduced above was really uninteresting. In XML data we usually find more than just two numbers. So let's see what we can do with a simple list of numbers:
The example we introduced above was really uninteresting. In XML data we usually find more than just two numbers. So let's see what we can do with a simple list of numbers:
Line 182: Line 312:
  height="{.}" fill="red" stroke="black"/>   
  height="{.}" fill="red" stroke="black"/>   
</source>
</source>
The full source code is below. We will not discuss the HTML5 version here, but below is link that will provide you code.


<source lang="xml">
<source lang="xml">
Line 208: Line 340:
   <xsl:template match="/">
   <xsl:template match="/">
     <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" >
     <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" >
      <!-- here we could draw a background rectangle -->
       <xsl:apply-templates/>
       <xsl:apply-templates/>
     </svg>
     </svg>
Line 226: Line 359:
</source>
</source>


Live example:
Live example (includes a background rectangle)
*
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro.xml intro.xml]
*
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro.xsl intro.xsl]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro-html5.xml intro-html5.xml]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro-html5.xsl intro-html5.xsl]


We also could procude a version for programmers who are scared of rule-based programming. You would use code like this:
We also could procude a version for programmers who are scared of rule-based programming. You would use code like this:
Line 234: Line 369:
<xsl:template match="list">
<xsl:template match="list">
  <xsl:for-each select="item">
  <xsl:for-each select="item">
     <rect x="{10*position()}" y="{100- .}" width="10" height="{.}" fill="red" stroke="black"/>      
     <rect x="{10*position()}" y="{100- .}" width="10" height="{.}"  
          fill="red" stroke="black"/>          
   </xsl:for-each>
   </xsl:for-each>
   </xsl:template>
   </xsl:template>
</source>
</source>


Live example:
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro-for.xml intro-for.xml]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro-for.xsl intro-for.xsl]
=== Creating a flexible simple bar chart ===
[[File:Xslt-svg-bar-chart2.png|200px|thumbnail|right|Screenshort of XML to SVG bar chart]]
The previous example has the flaw that height and width of the bars do not automatically adjust to:
* Size of the SVG canevas
* Number of items
* Maxium value in an item
The result should look like the picture to the right. The bar chart should fill in the provided SVG drawing canevas. Of course we also want to be able to deal with any (reasonable) set of positive numbers, i.e. the XML file could include more or less items and also different values.
Since this example includes some hairy tricks and introduces xslt variables and list processing, you can skip it and come back to it later ....
Firstly, we will allow users of this style-sheet to define the size of the canevas with XSLT variables.
<source lang="XML">
  <!-- you could change these in any way you like -->
  <xsl:variable name="svg_width" select="400"/>
  <xsl:variable name="svg_height" select="300"/>
  <xsl:variable name="padding" select="5"/>
</source>
Side note: XSLT variables are not really variable, i.e. you cannot reassign a value in the same context once it is set during runtime. For example, the following instruction:
<xsl:variable name="qual" select="engagement"/>
will bind the contents of the engagement element into a variable that can be recalled using the $ sign, i.e. $qual in our case. Each time XSLT executes a template, a new $qual binding will be created.
Back to our project. Knowing the canvas size is one of the information we need to handle width, height and position of the bars. We then must figure out how many items we have got. The next expression will compute the width of a bar as the width of the SVG canevas minus some padding divided by the number of items:
<source lang="XML">
  <!-- x-width with respect to N elements -->
  <xsl:variable name="x_width"
select="($svg_width - 2*$padding) div count(//list/item)"/>
</source>
We also need some sort of "y-step" that multiplied with the number will define the height. That will depend on the largest number in the item set. Finding a maximum in XSLT 1.0 is a pain. Typically, for such problems, I would google for an answer and wind up taking a solution from a cool web site like [http://stackoverflow.com/ stack overflow]. The next expression will compute the width of bar:
<source lang="XML">
  <xsl:variable name ="y_steps">
    <xsl:for-each select="//list/item">
      <xsl:sort select="." data-type="number" order="descending"/>
      <xsl:if test="position() = 1">
<xsl:value-of select="($svg_height - 2*$padding) div ."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>
</source>
The rest is now fairly easy. We just show the template for ''item'':
<source lang="XML">
  <xsl:template match="item">
    <rect x="{$padding + $x_width * (position() - 1) }"
  y="{($svg_height - $padding) - $y_steps * .}"
  width="{$x_width}"
  height="{. * $y_steps}"
  fill="red" stroke="black"/> 
  </xsl:template>
</source>
Live example:
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro-flexible.xml intro-flexible.xml]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/intro-flexible.xsl intro-flexible.xsl]
=== W3C example from the XSLT specification ===
The XSLT 1.0 specification includes a bar chart example that we slightly modified and adapted to HTML5. It demonstrates how to output text and it uses a a single template with "for-each" construct instead of templates defining how to render XML elements.
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/w3-xslt-svg-example.xml w3-xslt-svg-example.xml]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/w3-xslt-svg-example.xsl w3-xslt-svg-example.xsl]
== Creating simple cards from tabular information structures ==
Look first at the result:
* http://tecfa.unige.ch/guides/svg/ex/html5-xslt/xpath-jungle-links-1.xml
This file visualizes a simple information structure for projects. The XML file includes mainly two lists:
* participants: Each participant has a first name, engagement level and a description
* tasks: Each task includes a title, description, members that point to participants, difficulty and completion level, a list of ideas and a list of results.
Excerpt of the [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/xpath-jungle-links-1.xm XML] file:
<source lang="XML">
<?xml version="1.0"?>
<?xml-stylesheet href="xpath-jungle-links-1.xsl" type="text/xsl"?>
<project>
<title>The XSLT and SVG project</title>
<description>This project will explore some simple means to generate SVG from XSLT</description>
<participants>
  <participant id="p1">
    <FirstName>Daniel</FirstName>
    <engagement>4</engagement>
    <description>Daniel will be the project manager</description>
  </participant>
  ..........
</participants>
<tasks>
  <task id="t1">
    <title>Initial task</title>
    <description>Project preparation</description>
    <members><member idref="p1"/><member idref="p2"/></members>
    <difficulty level="3">This task should not be too hard</difficulty>
    <completion level="8">Fairly well understood so far</completion>
    <ideas>
      <item val="low">Buy a XSLT book</item>
      <item val="low">Buy an SVG book</item>
      <item val="high">Do some exploratory tiny examples</item>
    </ideas>
    <results>
      <result><a href="http://edutechwiki.unige.ch/en/XSLT_to_generate_SVG_tutorial">Wiki page</a> started</result>
      <result><a href="http://edutechwiki.unige.ch/en/XPath_tutorial_-_basics">XPath tutorial revised</a></result>
    </results>
  </task>
  .........
</tasks>
</project>
</source>
Below are the two most important XSLT fragments, and that would deserve some further explanation:
<source lang="XML">
<xsl:template match="participant">
  <div style="float:left;border-style:dotted;margin:10px;padding:5px;width:200px;height:200px;">
    <xsl:apply-templates select="FirstName"/>
    <xsl:variable name="qual" select="engagement"/>
    <svg style="background-color:yellow" width="100" height="100"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg">
      <circle id="greencircle" cx="{$qual*5}" cy="{$qual*5}" r="{$qual*5}" fill="green" />
    </svg>
    <xsl:apply-templates select="engagement"/>
    <xsl:apply-templates select="description"/>
  </div>
</xsl:template>
</source>


=== Introductory HTML5 variant ===
<source lang="XML">
<!-- task - programmed as a big block for change -->
<xsl:template match="task">
  <div style="float:left;border-style:solid;margin:10px;padding:5px;width:300px">
    <!-- title -->
    <p style="font-size:120%;">   
      <xsl:value-of select="position()"/>.
      <xsl:value-of select="title"/>
    </p>
    <p><xsl:value-of select="description"/></p>


    <!-- difficulty -->
    <p>Difficulty: <xsl:value-of select="difficulty"/></p>   
    <svg width="210" height="10"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg">
      <rect x="5" y="1" width="{difficulty/@level * 20}" height="5" fill="red" />
      <rect x="4" y="0" width="201" height="6" fill="none" stroke="black" />
    </svg>
   
    <!-- completion -->
    <p>Completion: <xsl:value-of select="completion"/></p>
    <svg width="210" height="10"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns="http://www.w3.org/2000/svg">
      <rect x="5" y="1" width="{completion/@level * 20}" height="5" fill="red" />
      <rect x="4" y="0" width="201" height="6" fill="none" stroke="black" />
    </svg>
    <xsl:apply-templates select="ideas"/>
    <xsl:apply-templates select="results"/>
  </div>
</xsl:template>
</source>
Source files:
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/xpath-jungle-links-1.xsl xpath-jungle-links-1.xsl]
* [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/xpath-jungle-links-1.xml xpath-jungle-links-1.xml]


== Work in progress ==
== Work in progress ==
(some may just need documentation and or tuning ... other will not work)
... plus old stuff that I may fix


Current
* http://tecfa.unige.ch/guides/svg/ex/html5-xslt/
* http://tecfa.unige.ch/guides/svg/ex/html5-xslt/
** http://tecfa.unige.ch/guides/svg/ex/html5-xslt/web-links.xml
Broken 12-year old stuff I may fix some day (project visualization)
* http://tecfa.unige.ch/guides/svg/ex/svg-xslt-visu/proj10-to-svg.xml
* http://tecfa.unige.ch/guides/svg/ex/svg-xslt-visu/visu-proj2.xsl (fixed it a bit so that the XML displays)
Various (only 8 year old or so, sort of works ...)
* http://tecfa.unige.ch/guides/svg/ex/svg-xslt/
Circles
* http://tecfa.unige.ch/guides/svg/ex/objects-in-circles/elements-on-circle-with-xslt.php


== Links ==
== Links ==


* [http://www.w3.org/People/maxf/papers/2002-07-SVGOpen/svgopen.html Using XSLT and SVG together: a survey of case studies] by Max Froumentin, Vincent Hardy, W3C, W3C/Sun Microsystems Inc. (2004). This is a somewhat outdated text, but I took some ideas from the introduction.
'''Tutorials'''
* [http://stackoverflow.com/questions/8056671/how-to-turn-an-xml-file-into-svg-using-xsl How to turn an XML file into SVG using XSL?], StackOverflow Question/Answer, 2011.
 
'''Outdated tutorials'''
 
Links below point to texts that include useful information since they attempt more ambitious stuff. However, some portions are outdated, in particular complaints about bad SVG implementations and server-side instead of client-side use of XSLT. But XSLT coding itself looks just about fine to me, but then I am not an expert in either SVG or XSLT - [[User:Daniel K. Schneider|Daniel K. Schneider]] ([[User talk:Daniel K. Schneider|talk]]) 19:00, 20 March 2013 (CET)
 
* [http://www.w3.org/People/maxf/papers/2002-07-SVGOpen/svgopen.html Using XSLT and SVG together: a survey of case studies] by Max Froumentin, Vincent Hardy, W3C, W3C/Sun Microsystems Inc. (2004). I took some ideas from the introduction for my introduction.
* [http://alistapart.com/article/usingxml Using XML] by J. David Eisenberg July 19, 2002 in AList Apart.
* [http://svground.fr/xslt-pour-svg.php XSLT pour SVG] (in french)
* [http://duane.freeshell.net/code/SVG_Tutorial/SVG_Tutorial.html Hands-On SVG Tutorial Using XML and XSLT] by Duane Odom
* [http://www.xml.com/pub/a/2004/09/08/tree.html Automated Tree Drawing: XSLT and SVG] by by Jirka Kosek, September 08, 2004. This interesting article is only suitable for real programmers, since it includes string parsing code.
* [http://xml.chez.com/exemples/xslt/barchart/index.htm Réaliser un histogramme en SVG (XSLT 1.0)] by Emmanuel Lazinier (2001). A bar chart in french, but the code is fairly self-explaining ....
* [http://www.carto.net/svg/samples/xslt/ Using XSLT to create SVG content] from carto:net. I fixed the code a bit: [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/carto-net-example.xml xml], [http://tecfa.unige.ch/guides/svg/ex/html5-xslt/carto-net-example.xsl XSLT].
* [http://www-106.ibm.com/developerworks/education/transforming-xml/xmltosvg/ Transforming XML to SVG], IBM developer works (broken link, shame on IBM who used to have "stable" contents). by Doug Tidwell, 2000/2001
* [http://www.svgopen.com/2003/papers/CreatingSVGPieChartsThroughWebService/index.html Creating SVG Pie Charts through XSLT via a Web Service] by Paul Asman 2001, An experience Report. (The XSLT code should still work an can be used independently).
 
'''Good examples''''
* [http://www.treebuilder.de/default.asp?file=85704.xml extending SVG with XSLT]
** For example: the [http://www.treebuilder.de/default.asp?file=677959.xml 3D Pie Chart]. If you like math, have a look at the [http://www.treebuilder.de/svg/extentSVG/version1/torte.xslt XSLT code], if you know some math look at the [http://www.treebuilder.de/default.asp?file=906871.xml simple bar chart] and its [http://www.treebuilder.de/svg/extentSVG/version1/barchart.xslt stylesheet]
* [http://xslorenz.gothick.org.uk/ XSLorenz] Lorenz Attractor fractal figure using only an XML document styled by an attached XSLT stylesheet, by Matt Gibson (2011).
 
[[Category: Visualization]]
[[Category: XML]]
[[Category: SVG]]

Latest revision as of 17:29, 22 August 2016

Introduction

This tutorial will teach you how to generate SVG graphics from XML data. We will produce both pure SVG and HTML5 embedded SVG.

Learning goals

  • Understand the purpose of XSLT, i.e. be able to think of XSLT as a translation language.
  • Do simple transformations from XML to HTML
  • Be able to use simple XPath expressions (tag and attribute names) in template selectors and for element and attribute extraction.
Prerequisites
Next steps

My first SVG from XML

Generating SVG with XSLT is really easy if you master some basic XSLT programming as explained in the XSLT Tutorial - Basics. Of course, you also should have some SVG basics.

At the time of writing, you can serve SVG in three different ways on the web:

  1. Embedded SVG in XHTML 1. This requires that you serve XHTML as XML. If you don't understand what that means, skip this option.
  2. Generate a pure SVG file. All modern browsers can display that.
  3. Generate an HTML5 file with inline SVG. All modern browsers can display that.

SVG Example level 0

We firstly will show how to produce some SVG graphic from the contents of a most simple XML document. We then show how to do this for HTML5.

Take the following XML file:

<?xml version="1.0" ?>
<?xml-stylesheet href="zero.xsl" type="text/xsl" ?>
<thing>
  <height>50</height>
  <width>100</width>
</thing>

We can imagine rendering this as a nice red rectangle. There we have to write a template that will extract contents of height and width and then use this to define the dimensions of the SVG rectangle. Absolute beginners should notice that the names of these XML tags do not matter, we also could have called these elements a and b...

Below is the XSLT code. As you can see, it is fairly straight forward. With respect to XSLT to HTML transforms, there are two differences:

  • We should declare the SVG namespace in the xsl:stylesheet root element on top
  • We should configure the output produced, else your browser may not want to display the SVG code.
<?xml version="1.0"?>

<xsl:stylesheet version="1.0" 
		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
		xmlns="http://www.w3.org/2000/svg"
		>
  <xsl:output
      method="xml"
      indent="yes"
      standalone="no"
      doctype-public="-//W3C//DTD SVG 1.1//EN"
      doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
      media-type="image/svg" />
  
  <xsl:template match="thing">
    <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
      <rect x="10" y="10" width="{width}" 
	    height="{height}" fill="red" stroke="black"/>  
    </svg>
  </xsl:template>
</xsl:stylesheet>

Now let us examine the template that deals with thing. We don't need a template for the root element (/). In the code above, the xsl template for thing will generate the top-level SVG tag.

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
   .....
</svg>

Next, we simply have to define an SVG rectangle and define the SVG attribute values for width and height with the values that we extract from the XML. In other words, {width} and {height} will be substituted by text found within <width> and <height> tags in the XML document.

<rect x="10" y="10" width="{width}" height="{height}" fill="red" stroke="black"/>

Live Code (may include slight variations):

HTML5 example level 0

Now let's produce HTML5. The principle is exactly the same, but the output declaration is a bit different and the template is longer since we will have to produced more code.

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" 
		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
		xmlns="http://www.w3.org/2000/svg"
		>
<xsl:output
     method="xml"
     doctype-system="about:legacy-compat"
     omit-xml-declaration = "yes"
     encoding="UTF-8"
     indent="yes" />
  
  <xsl:template match="thing">
   <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
       <meta charset="utf-8"></meta>
       <title>XHTML5 + SVG example</title>
     </head>
     <body>
       <p>This line is HTML, embedded SVG is below. Read the <a
       href="http://edutechwiki.unige.ch/en/XSLT_to_generate_SVG_tutorial">
       XSLT to generate SVG tutorial</a></p>

       <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
	 <rect x="10" y="10" width="{width}" 
	       height="{height}" fill="red" stroke="black"/>  
       </svg>
     </body>
   </html>
  </xsl:template>
  
</xsl:stylesheet>

Live Code (may include slight variations):

Visualizing some numbers

The following example (look at it) shows how to substitute a number by a bar that appears in elements of the list.

In the XML below, we would like to render the contents of the age element in a more interesting way:

<?xml version="1.0"?>
<?xml-stylesheet href="one-html5.xsl" type="text/xsl"?>
<project>
 <title>Simple XML to SVG demo</title>
 <people>
  <person>
    <FirstName>Kaspar</FirstName>
    <age>50</age>
    <description>A small man with a green tie</description>
  </person>
  <person>
    <FirstName>Jonathan</FirstName>
    <age>9</age>
    <description>A young person</description>
  </person>
  <person>
   <FirstName>Julie</FirstName>
   <age>30</age>
   <description>A young woman</description>
  </person>
 </people>
</project>

The XSLT uses fairly simple "rule-based" XSLT programming. The only template of interest concerns the age element. In addition, we add some more CSS styling to the HTML elements, e.g. div boxes with borders and we also will let the SVG top-level element float to the right.

Firstly, we store the value of the (current) element (i.e. the contents) of age in a variable called years. This is not necessary here, but allows simplifying complex XPath expressions. Note that a variable is used in an XPath expression with a $ sign in front, e.g. $years.

 <xsl:variable name="years" select="."/>

The SVG part then looks like this. Note how the rect height is computed as age*1.2

   <svg style="background-color:yellow;float:right" width="20" height="100" 
	xmlns:xlink="http://www.w3.org/1999/xlink" 
	xmlns="http://www.w3.org/2000/svg">
     <rect x="5px" y="5px" height="{$years*1.2}" width="10px" fill="green" />
   </svg>

Below is the full XSLT code:

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

<xsl:output
     method="xml"
     doctype-system="about:legacy-compat"
     omit-xml-declaration = "yes"
     encoding="UTF-8"
     indent="yes" />

 <xsl:strip-space elements="tasks participants"/>

 <xsl:template match="/">
   <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
       <meta charset="utf-8"></meta>
       <title>XHTML5 + SVG example</title>
     </head>
     <body>
       <p>XHTML5 contents below are generated from XML with XSLT. 
       Contents of and age elements are display in both text and with SVG as a green bar.
       Look at the source of this page for the XML and at the <a
       href="http://tecfa.unige.ch/guides/svg/ex/html5-xslt/one-html5.xsl">one-html5.xsl</a>
       file. Read the <a href="http://edutechwiki.unige.ch/en/XSLT_to_generate_SVG_tutorial">
       XSLT to generate SVG tutorial</a></p>
       <hr/>
       <xsl:apply-templates/>
     </body>
 </html>
 </xsl:template>

 <xsl:template match="people">
   <h1>People</h1>
   <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="person">
   <div style="border-style:dotted;margin:10px;padding:5px;width:200px;height:100px;">
     <xsl:apply-templates/>
   </div>
 </xsl:template>

 <xsl:template match="FirstName">
   <xsl:apply-templates/>,
 </xsl:template>

 <xsl:template match="age">
   Age: <xsl:apply-templates/>
   <xsl:variable name="years" select="."/>
   <svg style="background-color:yellow;float:right" width="20" height="100" 
	xmlns:xlink="http://www.w3.org/1999/xlink" 
	xmlns="http://www.w3.org/2000/svg">
     <rect x="5px" y="5px" height="{$years*1.2}" width="10px" fill="green" />
   </svg>
 </xsl:template>

 <xsl:template match="description">
   <p><xsl:apply-templates/></p>
 </xsl:template>

 <xsl:template match="title">
   <h1><xsl:apply-templates/></h1>
 </xsl:template>

</xsl:stylesheet>

Source files:

A more complex example is shown further down in the section Creating simple cards from tabular information structures

Creating a simple bar chart

The example we introduced above was really uninteresting. In XML data we usually find more than just two numbers. So let's see what we can do with a simple list of numbers:

Take the following xml file:

<?xml version="1.0" ?>
<?xml-stylesheet href="intro.xsl" type="text/xsl" ?>
<list>
 <item>10</item>
 <item>15</item>
 <item>12</item>
 <item>20</item>
 <item>5</item>
</list>

Such a list would render nicely as a bar chart:

The following code will do that. Of course it remains simple. E.g. good code would also compute a height and width parameter that takes into account both the data and the drawing space we want to use.

The difference between the "zero" example and this one is that we do some very simple math and also that we use XSLT functions count() and position().

  • The y coordinate of the rectangle is 100 minus the number found in the XML
  y="{100- .}
  • We use the count() function to figure out the number of item elements we got in the list.
    <rect x="10" y="105" width="{10 * count(item)}" 
	  height="5" fill="black" stroke="red"/>
  • Please also note that empty spaces between elements do count as nodes according to the XML standard. Therefore you must remove these empty nodes with the following instruction.
  <xsl:strip-space elements="list"/>
  • Each rectangle is positioned in the SVG according to its position in the XML list:
    <rect x="{10*position()}" y="{100- .}" width="10" 
	  height="{.}" fill="red" stroke="black"/>

The full source code is below. We will not discuss the HTML5 version here, but below is link that will provide you code.

<?xml version="1.0"?>
<!-- keep all three namespaces, xlink may not be needed, but the others are -->
<xsl:stylesheet version="1.0" 
		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
		xmlns:xlink="http://www.w3.org/1999/xlink"
		xmlns="http://www.w3.org/2000/svg"
		>
  
  <!-- **** output/input configuration -->
  
  <xsl:output
      method="xml"
      indent="yes"
      standalone="no"
      doctype-public="-//W3C//DTD SVG 1.1//EN"
      doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
      media-type="image/svg" />
  
  <!-- must remove white spaces within the list element, 
       otherwise count will not work -->
  <xsl:strip-space elements="list"/>
  
  <xsl:template match="/">
    <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" >
      <!-- here we could draw a background rectangle -->
      <xsl:apply-templates/>
    </svg>
  </xsl:template>
  
  <xsl:template match="list">
    <rect x="10" y="105" width="{10 * count(item)}" 
	  height="5" fill="black" stroke="red"/>
    <xsl:apply-templates/>
  </xsl:template>
  
  <xsl:template match="item">
    <rect x="{10*position()}" y="{100- .}" width="10" 
	  height="{.}" fill="red" stroke="black"/>  
  </xsl:template>
  
</xsl:stylesheet>

Live example (includes a background rectangle)

We also could procude a version for programmers who are scared of rule-based programming. You would use code like this:

<xsl:template match="list">
 <xsl:for-each select="item">
    <rect x="{10*position()}" y="{100- .}" width="10" height="{.}" 
          fill="red" stroke="black"/>            
  </xsl:for-each>
  </xsl:template>

Live example:

Creating a flexible simple bar chart

Screenshort of XML to SVG bar chart

The previous example has the flaw that height and width of the bars do not automatically adjust to:

  • Size of the SVG canevas
  • Number of items
  • Maxium value in an item

The result should look like the picture to the right. The bar chart should fill in the provided SVG drawing canevas. Of course we also want to be able to deal with any (reasonable) set of positive numbers, i.e. the XML file could include more or less items and also different values.

Since this example includes some hairy tricks and introduces xslt variables and list processing, you can skip it and come back to it later ....

Firstly, we will allow users of this style-sheet to define the size of the canevas with XSLT variables.

  <!-- you could change these in any way you like -->
  <xsl:variable name="svg_width" select="400"/>
  <xsl:variable name="svg_height" select="300"/>
  <xsl:variable name="padding" select="5"/>

Side note: XSLT variables are not really variable, i.e. you cannot reassign a value in the same context once it is set during runtime. For example, the following instruction:

<xsl:variable name="qual" select="engagement"/>

will bind the contents of the engagement element into a variable that can be recalled using the $ sign, i.e. $qual in our case. Each time XSLT executes a template, a new $qual binding will be created.

Back to our project. Knowing the canvas size is one of the information we need to handle width, height and position of the bars. We then must figure out how many items we have got. The next expression will compute the width of a bar as the width of the SVG canevas minus some padding divided by the number of items:

  <!-- x-width with respect to N elements -->
  <xsl:variable name="x_width"
		select="($svg_width - 2*$padding) div count(//list/item)"/>

We also need some sort of "y-step" that multiplied with the number will define the height. That will depend on the largest number in the item set. Finding a maximum in XSLT 1.0 is a pain. Typically, for such problems, I would google for an answer and wind up taking a solution from a cool web site like stack overflow. The next expression will compute the width of bar:

  <xsl:variable name ="y_steps">
    <xsl:for-each select="//list/item">
      <xsl:sort select="." data-type="number" order="descending"/>
      <xsl:if test="position() = 1">
	<xsl:value-of select="($svg_height - 2*$padding) div ."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

The rest is now fairly easy. We just show the template for item:

  <xsl:template match="item">
    <rect x="{$padding + $x_width * (position() - 1) }"
	  y="{($svg_height - $padding) - $y_steps * .}" 
	  width="{$x_width}" 
	  height="{. * $y_steps}"
	  fill="red" stroke="black"/>  
  </xsl:template>

Live example:

W3C example from the XSLT specification

The XSLT 1.0 specification includes a bar chart example that we slightly modified and adapted to HTML5. It demonstrates how to output text and it uses a a single template with "for-each" construct instead of templates defining how to render XML elements.

Creating simple cards from tabular information structures

Look first at the result:

This file visualizes a simple information structure for projects. The XML file includes mainly two lists:

  • participants: Each participant has a first name, engagement level and a description
  • tasks: Each task includes a title, description, members that point to participants, difficulty and completion level, a list of ideas and a list of results.

Excerpt of the XML file:

<?xml version="1.0"?>
<?xml-stylesheet href="xpath-jungle-links-1.xsl" type="text/xsl"?>
<project>
 <title>The XSLT and SVG project</title>
 <description>This project will explore some simple means to generate SVG from XSLT</description>
 <participants>
  <participant id="p1">
    <FirstName>Daniel</FirstName>
    <engagement>4</engagement>
    <description>Daniel will be the project manager</description>
  </participant>
  ..........
 </participants>
 <tasks>
  <task id="t1">
    <title>Initial task</title>
    <description>Project preparation</description>
    <members><member idref="p1"/><member idref="p2"/></members>
    <difficulty level="3">This task should not be too hard</difficulty>
    <completion level="8">Fairly well understood so far</completion>
    <ideas>
      <item val="low">Buy a XSLT book</item>
      <item val="low">Buy an SVG book</item>
      <item val="high">Do some exploratory tiny examples</item>
    </ideas>
    <results>
      <result><a href="http://edutechwiki.unige.ch/en/XSLT_to_generate_SVG_tutorial">Wiki page</a> started</result>
      <result><a href="http://edutechwiki.unige.ch/en/XPath_tutorial_-_basics">XPath tutorial revised</a></result>
    </results>
  </task>
  ......... 
 </tasks>
</project>

Below are the two most important XSLT fragments, and that would deserve some further explanation:

 <xsl:template match="participant">
   <div style="float:left;border-style:dotted;margin:10px;padding:5px;width:200px;height:200px;">
     <xsl:apply-templates select="FirstName"/>
     <xsl:variable name="qual" select="engagement"/>
     <svg style="background-color:yellow" width="100" height="100" 
	  xmlns:xlink="http://www.w3.org/1999/xlink" 
	  xmlns="http://www.w3.org/2000/svg">
       <circle id="greencircle" cx="{$qual*5}" cy="{$qual*5}" r="{$qual*5}" fill="green" />
     </svg>
     <xsl:apply-templates select="engagement"/>
     <xsl:apply-templates select="description"/>
   </div>
 </xsl:template>
 <!-- task - programmed as a big block for change -->
 <xsl:template match="task">
   <div style="float:left;border-style:solid;margin:10px;padding:5px;width:300px">
     <!-- title -->
     <p style="font-size:120%;">    
       <xsl:value-of select="position()"/>.
       <xsl:value-of select="title"/>
     </p>
     <p><xsl:value-of select="description"/></p>

     <!-- difficulty -->
     <p>Difficulty: <xsl:value-of select="difficulty"/></p>     
     <svg width="210" height="10" 
	  xmlns:xlink="http://www.w3.org/1999/xlink" 
	  xmlns="http://www.w3.org/2000/svg">
       <rect x="5" y="1" width="{difficulty/@level * 20}" height="5" fill="red" />
       <rect x="4" y="0" width="201" height="6" fill="none" stroke="black" />
     </svg>
     
     <!-- completion -->
     <p>Completion: <xsl:value-of select="completion"/></p>
     <svg width="210" height="10" 
	  xmlns:xlink="http://www.w3.org/1999/xlink" 
	  xmlns="http://www.w3.org/2000/svg">
       <rect x="5" y="1" width="{completion/@level * 20}" height="5" fill="red" />
       <rect x="4" y="0" width="201" height="6" fill="none" stroke="black" />
     </svg>
     <xsl:apply-templates select="ideas"/>
     <xsl:apply-templates select="results"/>
   </div>
 </xsl:template>

Source files:

Work in progress

(some may just need documentation and or tuning ... other will not work)

... plus old stuff that I may fix

Current

Broken 12-year old stuff I may fix some day (project visualization)

Various (only 8 year old or so, sort of works ...)

Circles

Links

Tutorials

Outdated tutorials

Links below point to texts that include useful information since they attempt more ambitious stuff. However, some portions are outdated, in particular complaints about bad SVG implementations and server-side instead of client-side use of XSLT. But XSLT coding itself looks just about fine to me, but then I am not an expert in either SVG or XSLT - Daniel K. Schneider (talk) 19:00, 20 March 2013 (CET)

Good examples'