Craig Rowe

Techlead / Developer

20th January 2010

XSL for Designers?

  1. Why Xsl?
  2. Similarities to CSS
  3. An XSL Stylesheet
  4. How can I try it myself?
  5. Example from Cargowire
  6. Final Points
  7. Appendix A: Current Context in XSL
  8. Appendix B: Declarative Vs Procedural XSL Stylesheets

At Headscape we use our own in house CMS. This technology is based on XML and XSLT with the XSL layer usually under the purview of the development team...

There is however, no reason why a proficient CSS user can't take advantage of, and work with XSLT. In fact, if the XSL is written in a more declarative, rather than procedural manner it can be very similar to working with CSS to style HTML.

Why Xsl?

XSL is a stylesheet language that can be used to 'transform' (the 'T' in XSLT) XML into some other output. I can go from:

            <item>
                <name nick="Craig">Craig Rowe</name>
                <company>Headscape</company>
                <group>colleague</group>
            </item>
        

to:

            <h3>Contacts</h3>
            <p class="colleague">
                <strong>Craig Rowe</strong> (Craig) from Headscape
            </p>
        

Although the transformation is from one text ouput to another we can see the similarities to applying CSS to HTML. With CSS the HTML starts off in one form, default browser styling renders it in a particular way (with fonts, padding, positioning), user CSS is then applied turning it into a slightly different visual output (different fonts, padding, positioning etc). In the XSL example above the only difference is that the final outcome is another type of text output rather than a graphical display.

In terms of the process we can imagine:

Backend Coder → generates → XML → transformed by → XSL → into → XHTML → styled by → CSS → ending in a → Beautifully designed website

The neat separation between content and presentation is immediately clear. If the 'engine' of an application created, used and output XML, then XSLT could be used to create any output without the need to modify a line of code. In fact this is how cargowire is created (as I've pointed to briefly before here and here). Multiple outputs are provided purely by leveraging XML and XSLT.

XSL, as a templating engine, is also backend language agnostic. That is to say I could go from running my site on .NET to running my site on PHP or Ruby but maintain the same XSL as long as I could generate the same semantic XML.

There are other benefits too... Many web APIs provide XML or RSS based outputs. Both of which can be transformed into HTML using XSL.

And it's not just us that use XSL. For example, Symphony CMS is a PHP based CMS solution that leverages XSL as its templating engine.

Similarities to CSS

Both CSS and XSL are tasked with selecting particular elements within a document and applying some kind of property or change to them. Let's compare the differing selection syntax. The following are equivalent:

CSS Selectors XSL Selectors (known as 'XPath') Plain English
1 div#content p.intro //div[@id='content']//p[@class='intro'] p with class 'intro' inside div with id 'content'
2 #container thead th //*[@id='container']//thead//th th inside thead inside any element with id 'container'
3 #content h3 //*[@id='content']//h3 h3 inside any element with id 'content'
4 #content > h3 //*[@id='content']/h3 h3 as direct child of element with id 'content'
5 #content, .content //*[@id='content'] | //*[@class='content'] Any element with id 'content' or class 'content'
6 ul.inline li:last-child //ul[@class='inline']/li[position()=last()]] The last li inside a ul with class 'inline'
7 //a/@href Select the href attribute of all anchor elements
8 . The current context node

Some of the syntax will be familiar to experienced CSS users. For example a[rel=external] is a CSS rule that is almost identical in XPath //a[@rel='external']. The key differences to be aware of are as follows:

  • There is no shorthand for the id or class of an element in xsl, they are merely attributes that need to be specified in square brackets.
  • The separator between sections of a css rule is usually a space or class/id shorthand. In XPath it is a / (direct child) or double // (any descendant)
  • The element type is required (note the use of * in rules 2-5 instead of merely starting with [@id=content])
  • The / or // separators are also required at the beginning of an XPath statement unless the statement is intended to start from the current context
  • Comma separating CSS selectors essentially means 'this or that'. With XPath this is represented by the pipe character | (rule 5).

If you want to test out these XPath selectors try the Firefox XPather plugin which allows you to type XPath selectors in a console window and see what results are returned from your html.

The XPather plugin window

An XSL Stylesheet

The template below could be used to transform the example data above. Do not be put off, it is very HTML esque with some opening tags at the top and a few document type declarations like xml version and output method, with the real meat in the centre.

            <?xml version="1.0" encoding="utf-8"?>
            <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

                <xsl:template match="/"><!-- Will match the root of the document and therefore run first -->
                    <xsl:call-template name="contacts" /><!-- Calls a template to run by name -->
                </xsl:template>
                
                <!-- A named template -->
                <xsl:template name="contacts">
                    <h3>Contacts</h3>     
                                          
                    <xsl:apply-templates select="//item" /><!-- Apply all rules/templates that match the selector -->
                    
                </xsl:template>
                
                <!-- A match/rule based template -->
                <xsl:template match="//item">
                    <p><!-- Attributes can be added as below or using curly brace shorthand e.g. class="{group}" -->
                        <xsl:attribute name="class">
                            <xsl:value-of select="group"/>
                        </xsl:attribute>
                        <strong>
                            <xsl:value-of select="name"/>
                        </strong>
                        <xsl:text> (</xsl:text>
                            <xsl:value-of select="name/@nick"/>
                        <xsl:text>) from </xsl:text><xsl:value-of select="company"/>
                    </p>
                </xsl:template>
                
            </xsl:stylesheet>
        

Like HTML, XSL files start and end with an angled bracket element (<xsl:stylesheet>) and can contain any number of templates, which themselves will contain any number of statements including plain text output. Any <xsl:...> tags are part of the stylesheet and not output. Any other elements, such as the H3 seen above, will be output as is.

How it works

When this template is applied to XML the following will happen:

  1. A template that matches the root element is looked for and run
  2. The root template has only one instruction, to call the 'contacts' template
  3. The contacts template will start by outputing an H3 for the 'Contacts' header
  4. The contacts template then tells the XSL processor to apply any templates that match the specified selector. In this case 'any element named item'
  5. The template that matches this selector is called for each 'item' element in the xml (in this case there is only one)
  6. Inside the item template (where the current context is the item node itself - so the selectors do not start with a slash)
    • The p element is output with an attribute named class set to the value of the 'group' node
    • A 'strong' element is output with the contents of the 'name' node inside it.
    • This is followed by the plain text backet before outputting the value of the name elements nick attribute, some more text and finally the company node contents.

As mentioned earlier and discussed in the notes below XSL stylesheets can have a distinctly procedural feel to them or a more declarative. In the template above we get a flavour of both. The more procedural style occurs where a template is called by name (line 6) - akin to a javascript method being called that document.write()'s. The more declarative style can be seen where templates are set up to 'match' a selector statement (line 13 and 18) with apply-templates being called to tell the xsl processor to match those rules.

How can I try it myself?

As a developer I mainly use XSLT from within a backend language (in my case, .NET which supports XSL 1.0) however many browsers are also XML/XSL aware so it is quite easy to test locally without any backend code knowledge simply by adding the reference to the stylesheet in the xml itself.

            <?xml-stylesheet type="text/xsl" href="items.xsl"?>
        

For an example of this please see items.xml and items.xsl (using view source to see the xml and xslt that is used). If you are using an XSL aware browser when you hit items.xml you should see the transformed html (which can be seen in firebug - view source will show the raw xml).

Using this technique the template generation can be done locally with example XML data before the intended application is even written. This can be used in conjunction with XPather for debugging.

Example from Cargowire

A more elaborate example can be garned from Cargowire itself. Last week I wrote about how Yahoo Pipes can be used to create an aggregate and filtered RSS feed. The output was a feed for the Headscape bloggers. On it's own this is useful for subscriptions however with XSLT we are able to present the content in an entirely different way.

The data source is standard RSS which we know is XML and can be transformed as such. A trimmed down version of the XSL for the barn page can be seen below. This transform occurs on the server side after code has retrieved the feed from Yahoo and before it sends a response to the user.

            <xsl:template match="//page/*/*/channel">
                <!-- Assumes a root matching template somewhere else in the XSL as well as the 
                definition of the gravatar template and $formatstring variable -->
              <p>This is simply a combined feed from <a href="http://www.boagworld.com" title="boagworld.com">Paul</a>, <a href="http://www.edmerritt.com" title="edmerritt.com">Ed</a>, <a href="http://www.davemcdermid.co.uk" title="davemcdermid.co.uk">Dave</a>, <a href="http://www.robborley.com" title="robborley.com">Rob</a> and <a href="/about#stalk">Myself</a></p>
              
                <div id="publicationLinks">
                  <dl id="publication">
                    <xsl:for-each select="item">
                        <dt>
                          <h3>
                            <xsl:choose>
                              <xsl:when test="string-length(link) > 0">
                                <a href="{link}">
                                  <!-- if this is an external link mark it as so -->
                                  <xsl:if test="not(starts-with(link, 'http://cargowire'))">
                                    <xsl:attribute name="rel">external</xsl:attribute>
                                  </xsl:if>
                                  <xsl:value-of select="title" />
                                </a>
                              </xsl:when>
                              <xsl:otherwise>
                                <xsl:value-of select="title" />
                              </xsl:otherwise>
                            </xsl:choose>
                            <!-- A call to a template to output the avatar image -->
                            <xsl:call-template name="Gravatar"/>
                          </h3>
                        </dt>
                        <dd>
                          <!-- call into some code to format the date after creating a variable -->
                          <xsl:variable name="datetimestampformat">
                            <xsl:text>yyyy-MM-ddTHH:mm:ss+00:00</xsl:text>
                          </xsl:variable>
                          <!-- use curly brace shorthand to use xsl/xpath to set an attribute value -->
                          <p class="published" title="{date:FormatDate(string(pubDate), $datetimestampformat)}">
                            <xsl:value-of select="date:FormatDate(string(pubDate),$formatString)" />
                          </p>
                          <p class="abstract">
                            <!-- Disable output escaping will maintain html tags in the output -->
                            <xsl:value-of select="description" disable-output-escaping="yes" />
                          </p>
                          <xsl:if test="string-length(link) > 0">
                            <a href="{link}" class="moreLink">
                              <xsl:if test="not(starts-with(link, 'http://cargowire'))">
                                <xsl:attribute name="rel">external</xsl:attribute>
                              </xsl:if>
                              <xsl:text>Read More...</xsl:text>
                            </a>
                          </xsl:if>
                        </dd>
                    </xsl:for-each>
                  </dl>
                </div>
            </xsl:template>
        

In the above stylesheet snippet we can see a template that matches the RSS channel element then loops through the items to produce an HTML based listing of the feed contents. Relatively self-describing constructs such as 'choose' and 'if' are used and so too are a couple of extras such as the call out to an external code object to format dates on line 33 and the use of not() and starts-with() on line 42. A variable is also defined on line 29 before being used on line 33.

If you want to find out more a good quick reference/start point for xslt 1.0 xpath and functions is provided by Mulberry Technologies.

Final Points

This article aimed to give you a taste of XSL and how it is used. As such we have kept to quite minimal templates and selectors however these core aspects of XSL should allow you to view and make ammendments to XSL templates without too much trouble. By using tools such as XPather and XSL in the browser you should be well equipped to make changes to and understand many XSL templates created by backend developers. It's also important to remember that although this example has discussed tranforming to HTML the output from XSL could just have equally been json, rss or even plain text.

The final example from Cargowire aims to illustrate a practical example and as such contains some more complicated functionality that is not fully described in this article. However if you are comfortable with HTML, CSS and perhaps a little javascript it should be relatively easy to follow.

Let me know your thoughts


Appendix A: Current Context in XSL

In XPath there are three main ways to start a selector:

  • /elementName - Finds the root element named elementName (in html only /html would match)
  • //elementName - Finds any instance of elementName in the entire XML document
  • elementName - Finds any instance of elementName as a direct child of the current context

In terms of the 'current context': If I was inside a template that had just matched 'item' an XPath of 'seconditem' would look for a direct child of the 'item' element that is named 'seconditem'. It would not match all 'seconditem' instances in the entire xml document.

In terms of CSS this could be seen as a rule that only applies to elements inside another rule. Or in jQuery a selector that runs from the 'this' context e.g jQuery('seconditem', this).

back - back to top

Appendix B: Declarative Vs Procedural XSL Stylesheets

It is my experience that many backend developers who move in to using XSL are keen to maintain the traditional coding paradigm of one thing following another until completion. Taking this view with XSL can lead to single large primary templates with many conditionals, loops and calling of sub templates.

This can make XSL difficult to read, particularly to non-technical users. However XSL is in its element when used declaratively. Instead of attempting to run down the XML as if parsing it in code simply define a number of rules that match the relevant parts and then apply those rules to the XML document (like CSS).

Lets look at a simple example comparison between two templates that do the same thing:

            <addressbook>
                <name>Work</name>
                <items>
                    <item>
                        <name nick="Craig">Craig Rowe</name>
                        <company>Headscape</company>
                    </item>
                    <item>
                        <name nick="Craig">Craig Rowe</name>
                        <company>Headscape</company>
                    </item>
                </items>
            </addressbook>
        
Procedural Style Declarative Style
                            <xsl:templates match="/">
                                <h2><xsl:value-of select="name"/></h2>
                                
                                <xsl:for-each select="items/item">
                                    <h3><xsl:value-of select="@nick" /></h3>
                                </xsl:for-each>
                            </xsl:template>
                        

This style has the look of javascript structure where loops and tests occur in sequence

                            <xsl:templates match="/">
                                <xsl:apply-templates select="items/name" />
                                <xsl:apply-templates select="items/item" />
                            </xsl:template>
                            
                            <xsl:templates match="name">
                                <h2><xsl:value-of select="."/></h2>
                            </xsl:templates>
                            
                            <xsl:template match="item">
                                <h3><xsl:value-of select="@nick" /></h3>
                            </xsl:template>
                        

This style has the look of a CSS structure i.e. a list of rules that match selectors

back to top

Sources / Related Links


All article content is licenced under a Creative Commons Attribution-Noncommercial Licence.