XML creation: Part 6

In this guide, I'll be creating an XML file to store the Playstation games I own, and ultimately make the XML file 'pretty' for Web browsers. I've done this in the past, with my vehicle gas XML document.

In part six I'll be using XSLT to modify the display of the XML document's contents so that it looks like the CSS-based output.

Last time ...

Up until now we've decided what we want to store, and how we want to store it, in an XML file.

Then, in part three, we actually added some of the data we want to store.

In part four, we made the XML file valid by associating a DTD.

Finally, in part five we started making the XML document pretty, in modern browsers, by using CSS.

Overview

Now that we've used CSS to stylize our XML document, and discovered some of the limitations of doing so, we'll use XSLT (Extensible Stylesheet Language Transformation) to modify the display.

As with the DTD and CSS creations, we'll need to make a modification to the XML document, as well as create the XSLT itself. 

The XML change

To begin, we'll need to remove the line we added last time, that points to the CSS file, and replace it with one that points to the XSLT file.

<?xml-stylesheet type="text/xsl" href="http://strivinglife.com/files/xml_creation/part6.xslt"?>

Obviously, update the location accordingly.

The XSLT

Let's begin by creating an empty file at the above location.

If we do so and load up our XML file, we'll see that this time there is an error when we try to display the file. This is because the XSLT must contain at minimum three lines.

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

If you try viewing the XML file now you'll be presented with the XML contents, one piece of text immediately after another. This is similar to what we saw before, when we used an empty CSS file.

This doesn't help us too much, so we'll try to tweak this a bit.

In order to do so, we'll add the following between the second and third lines of the above.

<xsl:template match="/">
   <xsl:value-of select="/games/game/title" />
   <xsl:value-of select="/games/game/system/console" />
   <xsl:value-of select="/games/game/system/version" />
   <xsl:value-of select="/games/game/purchase/date" />
   <xsl:value-of select="/games/game/purchase/price" />
   <xsl:value-of select="/games/game/purchase/place" />
   <xsl:value-of select="/games/game/sell/date" />
   <xsl:value-of select="/games/game/sell/price" />
   <xsl:value-of select="/games/game/own" />
   <xsl:value-of select="/games/game/notes" />
</xsl:template>

If you view the XML file now, you'll see the information for the first game, MotorStorm. This somewhat helps, but not completely.

Note that this is the same as doing the following instead.

<xsl:template match="games">
   <xsl:value-of select="game/title" />
   <xsl:value-of select="game/system/console" />
   <xsl:value-of select="game/system/version" />
   <xsl:value-of select="game/purchase/date" />
   <xsl:value-of select="game/purchase/price" />
   <xsl:value-of select="game/purchase/place" />
   <xsl:value-of select="game/sell/date" />
   <xsl:value-of select="game/sell/price" />
   <xsl:value-of select="game/own" />
   <xsl:value-of select="game/notes" />
</xsl:template>

What we really need to do is loop through each game. Of course, there is a way to do this.

<xsl:template match="games">
   <xsl:for-each select="game">
      <xsl:value-of select="title" />
      <xsl:value-of select="system/console" />
      <xsl:value-of select="system/version" />
      <xsl:value-of select="purchase/date" />
      <xsl:value-of select="purchase/price" />
      <xsl:value-of select="purchase/place" />
      <xsl:value-of select="sell/date" />
      <xsl:value-of select="sell/price" />
      <xsl:value-of select="own" />
      <xsl:value-of select="notes" />
   </xsl:for-each>
</xsl:template>

Updating and running with this, we see that we're now seeing what we got when we ran it with just the first two, and the last, lines.

Using the previous examples as a guide, we can get an idea of what we're doing.

First, we're using xsl:template match="games" to jump to the 'games' element. Next, for-each 'game' element, we're displaying the value of the elements listed.

Using /games/game/title, for instance, here, instead of title, would still give the value for the first instance of that element.

However, once again we're without proper spacing.

First, we'll use divs and spans around the elements that we'll want to style.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
 <xsl:template match="games">
  <div>
  <xsl:for-each select="game">
   <div>
    <span><xsl:value-of select="title" /></span>
    <xsl:value-of select="system/console" />
    <xsl:value-of select="system/version" />
    <div>
     <xsl:value-of select="purchase/date" />
     <xsl:value-of select="purchase/price" />
     <xsl:value-of select="purchase/place" />
    </div>
    <div>
     <xsl:value-of select="sell/date" />
     <xsl:value-of select="sell/price" />
    </div>
    <div>
     <xsl:value-of select="own" />
    </div>
    <div>
     <xsl:value-of select="notes" />
    </div>
   </div>
  </xsl:for-each>
  </div>
 </xsl:template>
</xsl:stylesheet> 

Refreshing our XML file, we see that some elements are beginning to become styled. We can complete the look by adding in the actual style information.

You may need to use &#160; for spacing. Try removing some from the below to see what happens with the display.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
 <xsl:template match="games">
  <div style="border:1px dashed #999;margin:.25em;padding:1em;">
  <xsl:for-each select="game">
   <div style="margin:1em 0;">
    <span style="font-size:120%;font-weight:bold;"><xsl:value-of select="title" /></span>
    &#160;<xsl:value-of select="system/console" />
    &#160;<xsl:value-of select="system/version" />
    <div style="margin-left:1em;">
     <xsl:value-of select="purchase/date" />
     &#160;<xsl:value-of select="purchase/price" />
     &#160;<xsl:value-of select="purchase/place" />
    </div>
    <div style="margin-left:1em;">
     <xsl:value-of select="sell/date" />
     &#160;<xsl:value-of select="sell/price" />
    </div>
    <div style="margin-left:1em;">
     <xsl:value-of select="own" />
    </div>
    <div style="font-style:italic;margin-left:1em;">
     <xsl:value-of select="notes" />
    </div>
   </div>
  </xsl:for-each>
  </div>
 </xsl:template>
</xsl:stylesheet> 

Finally, we'll add in the text that we were adding in with before/after in the CSS file.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
 <xsl:template match="games">
  <html>
  <head>
  </head>
  <body>
  <div style="border:1px dashed #999;margin:.25em;padding:1em;">
  <xsl:for-each select="game">
   <div style="margin:1em 0;">
    <span style="font-size:120%;font-weight:bold;"><xsl:value-of select="title" /></span>
    - <xsl:value-of select="system/console" />
    &#160;<xsl:value-of select="system/version" />
    <div style="margin-left:1em;">
     Bought <xsl:value-of select="purchase/date" />
     for $<xsl:value-of select="purchase/price" />
     at <xsl:value-of select="purchase/place" />
    </div>
    <div style="margin-left:1em;">
     Sold <xsl:value-of select="sell/date" />
     for $<xsl:value-of select="sell/price" />
    </div>
    <div style="margin-left:1em;">
     Still own? <xsl:value-of select="own" />
    </div>
    <div style="font-style:italic;margin-left:1em;">
     Notes: <xsl:value-of select="notes" />
    </div>
   </div>
  </xsl:for-each>
  </div>
  </body>
  </html>
 </xsl:template>
</xsl:stylesheet>

While IE 7 will display the elements as we'd expect, without the html and body elements, Firefox 2 will not.

At this point the XML file displays very similar in IE 7 as it does in Firefox, as well as how it displays in Firefox with CSS (with the exception of some slight padding, which we could nonetheless remove if needed).

If you'd like, you can view the XSLT document using your browser, since it is also an XML file.

Where we're at

At this point we're at a very good place. We've used XSLT to transform the display of our XML document so that it appears pleasing to the eye, in your standard, modern, browser. While a little more bulky than just using CSS alone, we can add important textual elements to the display, that would be difficult to do using simply CSS.  

What we're still missing

However, we're still missing some very important things; we need to be able to hide elements, like the sell information if the game hasn't been sold, as well as a proper sorting order.

In part 7 we'll go ahead and look at a new XSLT function that will allow us to sort the order of the displayed elements. I'll also add in some Playstation 2 games, so we can look at a more advanced display.