Five Quick Tips for Using XSLTby Dan Frumin
Like so many acronyms before it, XSLT (eXtensible Stylesheet Language Transformations) comes across as YAOT--Yet Another Obfuscated Technology. But it doesn't have to be that way. XSLT promises many advantages when applied to the right problems. All you need is a quick guide on using the XSLT basics. Once you start using it in your applications, I'll bet it will quickly come to be a useful tool in your belt.
So, what can we do with XSLT? In simple terms, XSLT is a transformation-based formatter. You can use it to convert structured XML documents into some other form of text output (quite often, HTML), though it can also generate regular text, comma-separated output, more XML, and so on. For this discussion, one of the main advantages of the technology is its ability to convert one or more information records in XML and format them into one of several HTML presentations. It's the old "abstract the presentation from the data" mantra. Not a bad thing to do, when called for.
Let me give you a concrete example. I've recently been working on the web site for my products company (SpiffyWare). In the process, I decided that I wanted to be able to easily add new products to the site, modify existing products, and even be able to modify or embed the presentation abstract of the actual product information. I had two options: I could use a database back end/front end (yikes, lots of development) or XML/XSLT. Since I didn't plan on having hundreds of products, XML/XSLT made sense. The result is that I use an XML file to describe the attributes of a product (e.g. the Name, Short Description, Long Description, Downloads, Licensing Options, System Requirements, etc.) and a series of XSLT files to display them.
Let's start with a very simple XML document for a product, and we'll build it up from there. For the time being, all we'll cover is the product title, version, and short description. Don't worry--we'll add more as we go along!
<product codename="Sparky"> <title>HtmlTransformer</title> <version>1.0</version> <short_desc> This product allows you to transform regular text into HTML and back. </short_desc> </product>
Now that we have the basic XML document set up, let's look at what we can do with XSLT.
1. The Basics
XSLT, like most other XML-based formats, is pretty picky about its structure. Your basic XSLT document looks like this:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" /> <xsl:template match="/"> Rules go in here... </xsl:template> </xsl:stylesheet>
What we see here is the declaration of the XSLT stylesheet, namespace, and
version. We're also telling the parser that we're outputting HTML.
All that is basic stuff. But what about the
XSLT is a rules-based language. That means the parser goes through and applies a set of rules (a template) to a certain set of elements (the match). The match is defined in the form of an XPath expression. XPath is a whole specification in and of itself, so I won't cover it in detail. If you are interested, the MSDN site has a pretty good reference on XPath from the MSXML 4.0 services release.
However, I can give you a few tips on XPath. First of all, we construct the XPath expression similar to a file system path, starting at "/" for the root element, and we can use ".." for the parent and "." for the self (the current node). There are a few other neat expressions we can use; a double slash represents not just the next level deep, but any level of depth. For example the XPath "a//b" means any descendant node "b" of the node "a", no matter how far down. Another useful trick is referring to an attribute. You can do this by using "@attribute" in the path. Last but not least, I'll point out that you can put expressions in the XPath, including tests on position and contents, but we won't cover that right now. I highly encourage you to read up on XPath in your favorite reference, or in the MSDN reference linked above.
So, for the time being, we know we have a basic stylesheet that matches the root element and does just about nothing. So let's do something.
Now that we have our basic document, we can work on adding something to the
output. We can do this using the
xsl:value-of tag and an XPath. For
<xsl:value-of select="product/title"/> <xsl:value-of select="product/version"/>
Will output the product's title and version. Since our template matches
the root element, we want to walk down to the product node and then the title
node. Of course, it seems rather curious that we're repeating the product
node path each time. Why are we doing that? Well, we have to ask
product a single element container (one product per XML file) or
will there be multiple products in a file? In our case, we'll say that the
XML file contains one and only one product. As such, we can move the
product node descriptor up to the
Ok, let's say we want to create output of the form: "Title Version (code:Codename)" and then the short description.
The resulting XSLT file looks like this:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" /> <xsl:template match="/product"> <xsl:value-of select="title"/> <xsl:value-of select="version"/> (code:<xsl:value-of select="@codename"/>) <br/><br/> <xsl:value-of select="short_desc"/> </xsl:template> </xsl:stylesheet>
You'll notice that we can add literal output strings (e.g. the parentheses) right into the rule set. However, if you run this through, you'll see something you might find slightly surprising. The title and the version are concatenated without a space. That's because when the XSLT file is being parsed, white space is ignored, as you might imagine from any structured XML file where we want to embed tabs and formats. How do we fix this?
xsl:text tag comes to the rescue. This tag tells an XSLT parser to
output the text in the tag verbatim. So, in order to embed a space, all we
have to do is add it between the
xsl:text tags. The result follows:
<xsl:value-of select="title"/> <xsl:text> </xsl:text> <xsl:value-of select="version"/>
So far so good, we have our product title, version, and codename out. Now let's add a few more interesting touches. Let's say that we want to store a list of downloads for each product. Downloads might include demos, papers, the help file, samples, etc. We'll start by defining the XML schema for these items:
<downloads> <item> <title>Free Demo Version</title> <filename>freedemo.exe</filename> <size>800K</size> <desc> This is the free demo version. </desc> </item> <item> <title>Help File</title> <filename>helpfile.hlp</filename> <size>200K</size> <desc> This is the help file for the product. </desc> </item> </downloads>
How do we output this information to our HTML? For this, we use the
xsl:for-each tag. This tag behaves as an iterator, working through each
node in a selection set and mapping the rules contained to each node. In
our particular case, we want to iterate through every item in the downloads node.
We can therefore use the following rule:
<xsl:for-each select="downloads/item"> Rules go in here... </xsl:for-each>
Inside of the tags we can use the tags we already know to output information about the downloads. A sample of our XSLT might look like this:
<br/><br/> Downloads Available: <br/> <xsl:for-each select="downloads/item"> <xsl:value-of select="title"/> (<xsl:value-of select="size"/>)<br/> <xsl:value-of select="desc"/> <br/><br/> </xsl:for-each>
Of course, it's not enough to just list the downloads. Ideally, we'd like to let the users get at the files. This requires linking the title of each download to a download path in the folder. If we start to write out the syntax, we end up with something like this:
<a href="<xsl:value-of select="filename"/>">
Clearly this won't work, as a result of the double-embedded tag set. In
order to address this problem, the
xsl:attribute tag is used. This tag
intelligently embeds an XSLT expression as an attribute into its parent output
tag. If this sounds complex, it's not. It's much easier to see it in
practice than to read it in a statement. Let's look at our example in
practice. In order to embed a link, we modify the above XSLT as follows:
<a> <xsl:attribute name="href"><xsl:value-of select="filename"/></xsl:attribute> <xsl:value-of select="title"/> </a>
You'll notice that the
xsl:attribute tag has its own "name" attribute.
This defines how the expression will be added to the parent output tag. In
this case, we're adding an
href attribute to the anchor (
a) tag, using the value
of the filename node as the expression. Could it be any easier?
Well, probably. But this isn't so bad.
This technique is also useful for outputting images where the image path (
and size (
height) are stored in the XML file. In this scenario,
each of these elements would get its own
So far we've covered the basics of XSLT. Now you know how to create
your own file, generate the contents of an HTML file, iterate over nodes, and
output complex tags. These five tips will get you most of the way into
XSLT and how to use it for your own HTML presentations. In fact, by now you probably know how to store multiple
products in a single XML file (use
xsl:for-each at the top), add screenshots
into the mix, and so on.
It's worth pointing out that XSLT does give us the ability to generate multiple views on the same XML file--one of its major strengths. For example, a single product.xml file that stores the product information, downloads, screenshots, and more can be used for a product summary page, the downloads list, a screenshot gallery, and more. The advantage is that adding or modifying a product requires no presentation changes--only data changes, a big win for any organization.
Final XSLT File
For those not keeping track, here's the final XSLT file we generated:
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" /> <xsl:template match="/product"> <xsl:value-of select="title"/> <xsl:text> </xsl:text> <xsl:value-of select="version"/> (code:<xsl:value-of select="@codename"/>) <br/><br/> <xsl:value-of select="short_desc"/> <br/><br/> Downloads Available: <br/> <xsl:for-each select="downloads/item"> <a> <xsl:attribute name="href"> <xsl:value-of select="filename"/></xsl:attribute> <xsl:value-of select="title"/> </a> (<xsl:value-of select="size"/>)<br/> <xsl:value-of select="desc"/> <br/><br/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Dan Frumin is a long-time technology executive, with over 10 years of experience in the industry.
Return to ONDotnet.com