All posts in "Tutorials"

The power of XSL (pt.1)

Published 26 December, 2006 in Programming , Tutorials , Xsl/Xslt - 0 Comments

I’m a lucky bastard! At work we use the beautiful Roxen CMS which utilize XSL for the entire templating system. I was a little bit familiar with XSL before we got Roxen CMS but I hadn’t really understood the power of it. It didn’t take long before I really started to love XSL.

My aim with this tutorial series is to shed some light on why I think XSL is so great and I hope that who ever reads this will get a more pleasant future (web development-wise that is).

I would like to make a note: I will not go through the fundamentals of XSL and XML here. I presume that some knowledge and preconception of programming and structure of XML already is at hand.

The X in XSL

As you already know, or have come to understand, XSL is used for styling or formatting, or parsing if you like, XML. XML is beautiful in that way that it is platform and device independent, standardized and read by virtually any programming language. XML data can be parsed, styled, used, displayed and so on in virtually any way and by any technique you can imagine.

So if any programming language can parse XML why do we need XSL? Well, the answer is quite simple: What if you by any reason have to implement your solution in a different programming language? You would have to rewrite everything and that’s not to fun. If you use XSL you can, as long as the language your moving to have an XSLT engine. So you could say that your solution becomes far more portable if it’s utilizing XSL.

Let’s begin with some code

Enough with the b s. In the first few examples we will use no programming language, the XSL transformation will be handled by an ordinary web browser. Both Gecko-based browsers (Mozilla*) and Internet Explorer handles client side XSL transformation. So we will only need an XML document and an XSL style sheet.

The XML

Here comes the XML we will start off with. I’ll use the classic discography example:

31 lines of XML
  1. <?xml version=“1.0” encoding=“ISO-8859-1”?>
  2. <discography>
  3. <artist>
  4. <name>Dream Theater</name>
  5. <country>USA</country>
  6. <album>
  7. <title>Images and words</title>
  8. <year>1992</year>
  9. <tracks>8</tracks>
  10. </album>
  11. <album>
  12. <title>Awake</title>
  13. <year>1995</year>
  14. <tracks>11</tracks>
  15. </album>
  16. </artist>
  17. <artist>
  18. <name>Dave Matthews Band</name>
  19. <country>USA</country>
  20. <album>
  21. <title>Under the table and dreaming</title>
  22. <year>1994</year>
  23. <tracks>11</tracks>
  24. </album>
  25. <album>
  26. <title>Crash</title>
  27. <year>1996</year>
  28. <tracks>12</tracks>
  29. </album>
  30. </artist>
  31. </discography>

Okey, there’s nothing strange about this. We have a structure with a depth of three nodes: discography --> artist --> album.

The XSL

First lets build an XSL skeleton. This is how we’ll start every XSL document:

4 lines of XSL
  1. <?xml version=“1.0” encoding=“ISO-8859-1”?>
  2. <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”>
  3. <!– We’ll insert our XSL code here –>
  4. </xsl:stylesheet>

Every XSL shall contain the xsl:stylesheet definition. The xmlns:xsl defines what name space we’ll be using, in this case the official one from W3C. We also say that we’ll be using version 1 of XSL transform.

This won’t do much for us. Let’s pop some more stuff in there. You can transform an XML document into a variety of other document formats; HTML, XML, Text and so on. Which format to output is done with the top level instruction xsl:output. Since this will be our main template we also need to write an instruction that will match the root node of our XML document (that is the discography node). To match a node we use xsl:template with the attribute match.

11 lines of XSL
  1. <?xml version=“1.0” encoding=“ISO-8859-1”?>
  2. <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”>
  3. <!– Output as HTML –>
  4. <xsl:output method=“html”/>
  5. <!– Match the root of our XML document –>
  6. <xsl:template match=“/”>
  7. <!– – This is where we’ll start our HTML code —>
  8. <h1>Code goes here</h1>
  9. </xsl:template>
  10. </xsl:stylesheet>

Before we do an initial test we need to assign the XSL to the XML. This is done in a similar way as assigning a CSS to an HTML document (). To assign an XSL to an XML we need to “import” the XSL in the XML:

5 lines of XML
  1. <?xml version=“1.0” encoding=“ISO-8859-1”?>
  2. <?xml-stylesheet type=“text/xsl” href=“the-xsl.xsl”?>
  3. <discography>
  4. <!– … –>
  5. </discography>

Okey, so lets save the XML as discography.xml and the XSL as discography.xsl in a folder and load the XML in our browser. The result should look something like below:

Example 1

Game, set xsl:template match

Okey, the first output here is not that exciting, so lets move on to some more interesting code. Let us put some HTML in our XSL template so we can see the basic structure:

18 lines of XSL
  1. <?xml version=“1.0” encoding=“ISO-8859-1”?>
  2. <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”>
  3. <!– Output as HTML –>
  4. <xsl:output method=“html”/>
  5. <!– Match the root of our XML document –>
  6. <xsl:template match=“/”>
  7. <html>
  8. <head>
  9. <title>My CD collection</title>
  10. </head>
  11. <body>
  12. <h1>My CD Collection</h1>
  13. <xsl:apply-templates/>
  14. </body>
  15. </html>
  16. </xsl:template>
  17. </xsl:stylesheet>

Except for the basic HTML here the one interesting thing to note here is the instruction xsl:apply-templates. In a way we’re gonna loop (not in the way as ordinary loops in regular programming languages, although you can do that too in XSL, but that I’ll leave for now) through the XML document and you can say that xsl:apply-templates just passes on the XML data to the next matching rule. Remember: we have xsl:template match="/" which matches the root of our XML document. Now we’re gonna write some more xsl:template match="..." instructions that will match the root’s child nodes.

We have the following structure: discography --> artist --> album. So we’ll write one xsl:template match="..." for each one of them. I’ll leave out the XSL skeleton now just for space reasons:

22 lines of XSL
  1. <xsl:template match=“discography”>
  2. <xsl:apply-templates/>
  3. </xsl:template>
  4. <xsl:template match=“artist”>
  5. <h2>
  6. <xsl:value-of select=“name”/>
  7. <xsl:text> </xsl:text>
  8. <small><xsl:value-of select=“country”/></small>
  9. </h2>
  10. <ul><xsl:apply-templates select=“album”/></ul>
  11. </xsl:template>
  12. <xsl:template match=“album”>
  13. <li>
  14. <strong><xsl:value-of select=“title”/></strong>
  15. <xsl:text> </xsl:text>
  16. <small>(<xsl:value-of select=“year”/>)</small>
  17. <br/>
  18. <xsl:value-of select=“tracks”/> tracks
  19. </li>
  20. </xsl:template>

So what’s happening here is that we first match the discography node and just continue applying templates. It may seem unnecessary to have this template since all we do is continue applying templates but if we had left this template out the discography node from the XML document would be output in our resulting HTML document. (There’s other ways to handle this but that’s out of the scope for now).

The xsl:apply-templates in the discography template will move us on to the artist template. The artist node have a child node named name. The value of this node we output with .

To output whitespace in XSL we use and that’s what we’re doing to get a space between the value of the name node and the value of the country node. Now we’re done with the artist node so let’s move on to the album node by xsl:apply-templates. Note that I’ve added select="album" in the xsl:apply-templates here. The reason for this that when ever XSL find nodes it can not find a template for it just outputs that node into the result. If you remove the select="album" you’ll see that the artist name and country will be output twice. To prevent this we specify that we want to apply-templates for the artist node and thus we catch that node there and we’ll be fine. There are several ways to fix this but that’s a more advanced action so I leave that out for now.

There’s nothing new in the album template so we need no further explanation there.

The entire XSL

41 lines of XSL
  1. <?xml version=“1.0” encoding=“ISO-8859-1”?>
  2. <xsl:stylesheet version=“1.0” xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”>
  3. <!– Output as HTML –>
  4. <xsl:output method=“html”/>
  5. <!– Match the root of our XML document –>
  6. <xsl:template match=“/”>
  7. <html>
  8. <head>
  9. <title>My CD collection</title>
  10. </head>
  11. <body>
  12. <h1>My CD Collection</h1>
  13. <xsl:apply-templates/>
  14. </body>
  15. </html>
  16. </xsl:template>
  17. <xsl:template match=“discography”>
  18. <xsl:apply-templates/>
  19. </xsl:template>
  20. <xsl:template match=“artist”>
  21. <h2>
  22. <xsl:value-of select=“name”/>
  23. <xsl:text> </xsl:text>
  24. <small><xsl:value-of select=“country”/></small>
  25. </h2>
  26. <ul><xsl:apply-templates select=“album”/></ul>
  27. </xsl:template>
  28. <xsl:template match=“album”>
  29. <li>
  30. <strong><xsl:value-of select=“title”/></strong>
  31. <xsl:text> </xsl:text>
  32. <small>(<xsl:value-of select=“year”/>)</small>
  33. <br/>
  34. <xsl:value-of select=“tracks”/> tracks
  35. </li>
  36. </xsl:template>
  37. </xsl:stylesheet>

The result of this should look something like below:

Example 2

And that’s that for this time…