beta it republik » Articles

Articles

Untitled Document
Thursday, 17 July 2008 | Article

<root> Elements

Modern markup languages such as XHTML, and the metalanguages that define them (in this case XML), are built from a set of nodes, or elements. The top level, or root element of any such language opens the document and is the container, or parent, for the rest of the elements that follow. In an HTML document, for instance, the root element is <html>. So the focus of this column is the starting point of any development task. Bootstrapping, to use an operating system metaphor.


Introduction
The first time I looked at an XSLT stylesheet, I couldn’t make heads or tails of it. Some parts of it looked familiar; in fact, most of it was HTML. The other parts, with their named nodes containing the strange <xsl:whatever> tags looked a bit strange. The syntax inside most of those nodes looked familiar—here and there you could see a ‘for each’, for instance—but the entire mass seemed impenetrable.

So I decided to take it one bit at a time until I’d figured out a way to make sense of it all. Along the way, I tossed out everything I didn’t need to know at the moment and started small. Then I added in the rest of it until I had just enough knowledge to get me through 80% of the tasks in front of me. It’s the way I learn, and it’s how I see most of my comrades in the programming world climb the long learning curve when faced with something unfamiliar.

In this article, we are going to start small. By the end of the piece, you should have more than enough information to get you through most of the XSLT situations you’ll face as a developer.

So What Is XSLT?
Let’s start with the basics. XSLT stands for eXtensible Stylesheet Language for Transformation. All around the world, right now, in fact, developers use XSLT to transform XML into something else, usually HTML for rendering in a browser. Although it has many properties similar to Cascading Style Sheets, or CSS, (it can be used to apply styling to HTML as it is rendered, for instance) it is much more powerful.

In fact, think of XSLT as yet another programming language. Although it is not as sophisticated as PHP or Python, it is much more than mere markup or stylesheet decoration. The different commands in XSLT allow you to find the nodes you want to
transform, to loop over them, sort them, number them, count them, and perform many operations that are impossible with CSS.

In this article, we’re going to use one XML file as our basis for transformations. Just picking something at random as I write this article, I decide that this XML file will contain a listing of computer games that are within my line of sight on my desk right now. As you will see from the next listing, each computer game I see is recorded, along with data about each game.

The first thing you should notice about Listing 1, saved as games.xml, is that the root node for the listing is <games>. Under this root node is a <title> node, which holds the title for the entire listing. What follows is a series of <game> nodes, each with its own unique ID attribute and other information, such as <title>, <maker>, and so on.

As we get the hang of XSLT, we’ll be taking special notice of how this XML document (or collection, if you will) is treated and processed by XSLT. The first thing to realize is that you will have to process the XML nodes with specific addresses. For example, the text that contains the title for the entire game list can be found by following a logical path that looks like this:

games->title

However, the title for any individual game requires a more specific path that includes the use of a unique ID attribute for a particular game. If we wanted to find the title “Black and White” we would have to follow this path:

games->game[4]->title

Following these paths is done with XPath, but more on that later.

Building our First XSLT
As useful and tidy as our games.xml document is, it doesn’t make for a very good display in a browser. If you point your browser at this file, you will see something like the illustration shown in Figure 1. It’s just a series of nodes, and it’s not very attractive.

Listing 1
<?xml version=”1.0” encoding=”utf-8”?>
<games>
<title>Computer Games</title>
<game id=”1”>
<title>Medal of Honor Allied Assault</title>
<maker>EA Games</maker>
<format>CD</format>
<advisory>Teen</advisory>
</game>
<game id=”2”>
<title>Freelancer</title>
<maker>Digital Anvil</maker>
<format>CD</format>
<advisory>Teen</advisory>
</game>
<game id=”2”>
<title>Civilization III</title>
<maker>Atari</maker>
<format>CD</format>
<advisory>Everyone</advisory>
</game>
<game id=”3”>
<title>First to Fight</title>
<maker>Destineer</maker>
<format>CD</format>
<advisory>Teen</advisory>
</game>
<game id=”4”>
<title>Black and White</title>
<maker>Lionhead</maker>
<format>CD</format>
<advisory>Teen</advisory>
</game>
</games>


Our goal is to take this bunch of XML nodes and make them into a nice listing. We’re going to do that with XSLT. However, before we do that, we need to cover some basics.

For those of you who are still a bit nervous about XSLT, just keep telling yourself that XSLT is just another XML document. It follows all the rules of XML, such as:
  • It has to have a root node that contains other nodes
  • Each node inside the document must have an opening and closing tag (empty nodes can be closed with a trailing slash, as in <br/>)
  • Spelling and capitalization count here as much as it does with any XML document

In fact, the only thing that is vastly different about XSLT is that it uses namespaces to a greater degree than you’re used to. Before we get into all that, let’s start off on the right foot—by adding in the information that all XSLT documents need to have [to do their job]. See Listing 2.

Simple, right? In the first line, we put in the XML declaration. This isn’t required for it to work, but it keeps you out of mischief. The second line, the <xsl:stylesheet> line, is a bit more complicated, but this node is the parent node for all the rest of the instructions in the stylesheet.

Inside the <xsl:stylesheet> node are two attributes, version and xmlns:xsl. The version attribute is self-explanatory. The xmlns:xsl attribute holds a URI for the stylesheet’s namespace, which in this case is xsl.


Listing 2
<?xml version=”1.0” encoding=”utf-8”?>
<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>
<xsl:output method=”html”/>
</xsl:stylesheet>


What’s a namespace? Why do we need one? I’ll explain it this way. Let’s say you are running a bookstore and I’m running a realtor’s office. We want to share XML files for whatever reason, and we send each other our data. Suddenly, we have a problem. Why? Because your data file contains node snippets like this:

<book>
<title>Gone with the Wind</title>


and my data file contains snippets like this:
<record>
<title>189300z8-03-2-23-xyz</title>


Your <title> tag is used to record titles of books, while my <title> tag is used to record the title to a deed of land. Oops. How could we have avoided this unfortunate collision? By using namespaces. Your namespace might be book and mine, land. Suddenly, there isn’t a problem:

<book:book>
<book:title>Gone with the wind</book:title>
…..
<land:record>
<land:title>189300z8-03-2-23-xyz</land:title>



With XSLT, it works the same way. Remember that you’re going to have a lot of markup (mostly HTML) in your instructions, so XSLT needs to know which tags should be acted upon. In our case, since we’re using XSLT’s default namespace of xsl, any tag with a prefix xsl: will be processed by XSLT.

Also notice that we’ve declared the xsl namespace the very first time we use it, inside the <xsl:stylesheet> node. The rules of namespacing stipulate that you can declare a namespace anywhere you want. However, the namespace is only valid for all nodes nested under the element you use to declare the same namespace. In our case, the xsl namespace is good for the entire stylesheet and all of its operations.

Some of you may be wondering if there’s ever a good time to declare a namespace at a later point, and the answer is yes, if you only want a namespace to effect a much smaller set of nodes.


However, for the purposes of this article, we’ll stick to declaring our namespace at the root element. Makes things simpler that way. Enough for now. What’s the next instruction?

<output method=”html”/>

This simple command tells XSLT that we are going to be outputting to HTML. There are other output methods available, but for now, this is all you need to know.

The final thing to figure out is how do we tie the XML and XSLT together? By adding a simple line to our XML document that tells it where the XSLT is. If we save the XSLT file as games. xsl, we can add a simple processing instruction to the XML file to tell it where to look:

<?xml-stylesheet href=”games.xsl” type=”text/xsl”?>

If you were to point your browser at your XML file again, you’d see nothing. Why? Because we haven’t done anything yet! We need to add our first transformation.

Adding our First Template
In XSLT, at least at this level, you primarily work with templates. Think of templates as a set of regular expressions or search queries. Basically, with a template, you’re trying to match a node in the incoming XML and then perform some kind of action, such as print out text or transform the XML you see into something else.

Our first job is to write a template that will match on the root node of our games.xml document and then print out a simple bit of HTML. Once we get the hang of that, we’ll do something a bit more complicated.

The result is not very exciting at all, but that’s beside the point. You’ve written your first XSLT template! Take a moment to pat yourself on the back. In your browser, you should see something like the next screenshot (Figure 2).


Fig. 1: XSLT template output


Enough celebrating. Let’s put some meat on those bones. Instead of printing out some simple HTML, let’s print out the title of the game list. We can do that with XPath. All we have to do is walk down a path of nodes until we find what we want to print, and then print it out using a special command called value-of.

If you refresh your browser, you should see “Computer Games” in your browser. XSLT helpfully transformed the <title> node under <games> to an <h1> for us. The next step in the process will involve creating a neat, orderly table that will list out all of the games in our XML listing.


Fig. 2: The ‘Computer Games’ table


Listing 3
<?xml version=”1.0” encoding=”utf-8”?>
<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>
<xsl:output method=”html”/>
<xsl:template match=”/”>
<h1>Hello, I see you!</h1>
</xsl:template>
</xsl:stylesheet>



Listing 4
<?xml version=”1.0” encoding=”utf-8”?>
<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>
<xsl:output method=”html”/>
<xsl:template match=”/”>
<h1><xsl:value-of select=”/games/title”/></h1>
</xsl:template>
</xsl:stylesheet>


Using for-each to Build a Table
In this next part, we’re going to create a table of our game listing that will look very much like the screenshot in Figure 3.

How do we do that? Remember when I said XSLT is a lot like other programming languages? XSLT has a foreach command that acts a lot like foreach in PHP or Perl. The foreach looping construct allows you to loop over a series of nodes.

In our case, now that we’re inside the root node with our initial template match and have successfully printed out the title “Computer Games”, we can now loop over the rest of the <game> nodes to get at the information inside of them. I’ll put the entire code snippet in front of you and then we’ll walk through it in detail.

The first lines of the bolded section are simple enough—all we’re doing there is printing out the HTML necessary to declare an HTML table and the header row. Then comes this line:


<xsl:for-each select=”//game”>

The for-each command allows you to loop over a selected snippet of nodes. In this case, remember that you have already stepped inside the root node (the template match on / above this line) so all we have to do is match all the rest of the <game> nodes. In XPath, you can match all nodes of the same name by putting // in front of the node name in your select statement. This can be a bit dangerous if you don’t know what might happen, but in this case, we know that all <game> nodes are what we need.

In the next line, we print out an HTML <tr> element, followed by each of the data elements we want to extract from each node inside of <game>, wrapping each of those in HTML <td> elements to make our columns. Again, we’re going to make good use of value-of.

In the first column, we want to print out the value of the id attribute associated with a <game>. To work with attributes, you have to place a @ symbol in front of them in your select statement. Thus, the command <xsl:value-of select=”@id”/> means “select the id attribute for the <game> node we are processing at the moment”.

All the other value-of statements are straightforward; all we’re doing is grabbing the content for each <title>, <maker>, and <advisory> node we see in each <game>.

Listing 5
<?xml version=”1.0” encoding=”utf-8”?>
<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>
<xsl:output method=”html”/>
<xsl:template match=”/”>
<h1><xsl:value-of select=”/games/title”/></h1>
<table border=”1” cellspacing=”0” cellpadding=”5”>
<tr>
<th>id</th>
<th>title</th>
<th>maker</th>
<th>advisory</th>
</tr>
<xsl:for-each select=”/ /game”>
<tr valign=”top”>
<td><xsl:value-of select=”@id”/></td>
<td><xsl:value-of select=”title”/></td>
<td><xsl:value-of select=”maker”/></td>
<td><xsl:value-of select=”advisory”/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>


The result is an HTML table that summarizes our game collection.

Making It All Look Good
In the last section, we created a table, but it’s not that aesthetically pleasing. In this section we’ll try to add some beauty to the beast. We can do this any number of ways, including embedding style right into each individual HTML tag, but that isn’t too smart.

For the purposes of this article, I’m going to create a style section right in the HTML output, but for bigger projects, it’s probably smarter to create a separate CSS stylesheet and then link to it.

When you refresh your browser, you’ll notice that the fonts are all in a pleasing Arial and that there’s more space, 10 pixels worth, from the left side of the screen. We’ve also added some background color to all the header cells along the top of the table.

Using the same techniques, you can add as much CSS styling as you like. For now, though I want to move on to counting and sorting.

Listing 6
<?xml version=”1.0” encoding=”utf-8”?>
<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>
<xsl:output method=”html”/>
<xsl:template match=”/”>
<html>
<head>
<title><xsl:value-of select=”/games/title”/></title>
<style>
body{
font-family:Arial, Verdana, sans-serif;
padding: 10px;
}
th{
background-color:#ccc;
}
</style>
</head>
<body>
<h1><xsl:value-of select=”/games/title”/></h1>
<table border=”1” cellspacing=”0” cellpadding=”5”>
<tr>
<th>id</th>
<th>title</th>
<th>maker</th>
<th>advisory</th>
</tr>
<xsl:for-each select=”//game”>
<tr valign=”top”>
<td><xsl:value-of select=”@id”/></td>
<td><xsl:value-of select=”title”/></td>
<td><xsl:value-of select=”maker”/></td>
<td><xsl:value-of select=”advisory”/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>


Adding a Count of Games
Now that we have a reasonably good-looking table that represents our list of games, let’s add a count of games to the display. We can count any nodes we want, using XSLT’s count() function. All we have to do is tell it which nodes to count, and it will return a number. We’ll put our count right after the initial <h1> transformation.

First the code:

<h1><xsl:value-of select=”/games/title”/></h1>
<p>Total games in collection: <xsl:value-of select=”count(//game)”/></p>


The result should look like the screenshot shown in Figure 4. For the last bit, we’re going to change the order of the XML contents by using the sort command.


Fig. 3: Count the nodes in the table



Fig. 4: Sort the games in the table by title



Fig. 5: Sort the games in the table by ‘teen’


Sorting the Games
Normally, XSLT works its magic by working on the nodes of an XML document in the order it sees them. However, by using the sort command, which in this case we’re going to put directly after our for-each command, you can change the display of the games in our listing.

In this case, I decided to sort the listing by <title>. The result should look like the screenshot in Figure 5.

You can change the sort order to descending by adding an order attribute with a value of descending to the sort command, like this:

<xsl:sort select=”title” order=”descending”/>

The final thing we’re going to do in this article is use the conditional if to only print out those rows that meet a certain criteria.

In a departure from the norm, the if command uses a test instead of a select, but the effect is similar. In our test, we state that we only want those games where the <advisory> node contains the text “Teen”. The result should look like the screenshot in Figure 6.

Listing 7
<xsl:for-each select=”//game”>
<xsl:sort select=”title”/>
<tr valign=”top”>
<td><xsl:value-of select=”@id”/></td>
<td><xsl:value-of select=”title”/></td>
<td><xsl:value-of select=”maker”/></td>
<td><xsl:value-of select=”advisory”/></td>
</tr>
</xsl:for-each>


Listing 8
<xsl:for-each select=”//game”>
<xsl:sort select=”title”/>
<xsl:if test=”advisory=’Teen’”>
<tr valign=”top”>
<td><xsl:value-of select=”@id”/></td>
<td><xsl:value-of select=”title”/></td>
<td><xsl:value-of select=”maker”/></td>
<td><xsl:value-of select=”advisory”/></td>
</tr>
</xsl:if>
</xsl:for-each>


What if we wanted to only display those games that matched a certain id attribute for a <game> node? We would only have to modify our test slightly, using @id instead of advisory, and an integer instead of a string:

<xsl:if test=”@id=’2’”>

The result would look like the screenshot in Figure 7.


Fig. 6: Sort the table by ID


Listing 9
<?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”/>
<xsl:template match=”/”>
<games>
<title><xsl:value-of select=”/games/title”/></title>
<xsl:for-each select=”//game”>
<xsl:variable name=”newid”><xsl:value-of
select=”@id”/></xsl:variable>
<game gameid=”{}”>
<name><xsl:value-of select=”title”/></name>
<mfg><xsl:value-of select=”maker”/></mfg>
<advisory><xsl:value-of select=”advisory”/></
advisory>
</game>
</xsl:for-each>
</games>
</xsl:template>
</xsl:stylesheet>



What’s the Point?
If you’ve been following along, you’re bound to notice that after creating the XML document, we never touched it again. All of our work was done in the XSLT file. We deftly separated our content (or data, if you will) from the presentation logic in our XSLT.

Tomorrow, if we need to change our display, we can tweak our XSLT to meet the requirements. If we need to display our XML document on a PDA, we can create a new pda.xsl file and create WML. We can even use XSLT to transform our existing XML into another idiom of XML to share with another system. Perhaps they don’t use the <maker> element, but instead use <mfg>. They don’t use an id attribute; theirs is name gameid. And instead of <title> they use <name>.

The following XSLT (translate.xsl) would solve all those problems without affecting our original document:

Notice the line directly after the for-each loop. We’re using an xsl:variable to store the results of the id attribute in a variable called newid. Then we simply print the value of that variable where we need it. But we’re getting way ahead of ourselves—all I want for you to take away from the exercise is a feel for the power of using multiple stylesheets to transform an XML document into any number of results.

Summary
You’ve survived your first foray into the world of XSLT. You’ve learned some basics about namespaces, how to match a root node, how to loop through a series of nodes, how to print out both elements and attributes, and how to count, sort, and use conditional logic. There’s a whole bunch more to learn—XSLT is a huge knowledge domain—but with any luck this introductory article has given you the push you need to do something productive.



About the Author

Thomas Myer is the founder of Triple Dog Dare Media, an Austin, TX web consultancy that specializes in content management systems. He is the author of No Nonsense XML Web Development with PHP, recently published by Site Point. You can find out more about the book at http://www.tripledogs.com/xmlbook. You can email him at tom@tripledogs.com


   Related Links


Comment

Name:

Comment:

Captcha Verification !
captcha_image