I believe XSL is more underused than it should be. Few people at the recent code camp were familiar with it and it is my experience that people are aware of it and what it does but may not know how it does it.

XSL is used to convert an XML document into another format. The other format can be another XML document, HTML, text or any other format (and as far as I know, it has to be a text-based format). There are many good tutorials on XSL (my favorite resource is here; check out the Questions and Answers section) so I'm going to focus on a couple of the more obscure things.

xsl:apply-templates vs. xsl:for-each
While XSL is underused, the xsl:for-each construct is, in my opinion, overused. People use it because they understand it. It has a direct correlation to modern programming languages and programmers know intuitively how it works. I almost never use it.

The next time you want to put in an xsl:for-each, consider using a separate template instead. That's what templates are for. Say, for example, you are building a table to display a list of Songs. Your XML would have a Songs root element with one or more Song elements. And perhaps each Song element has one or more Genre elements.

This, to me, warrants three templates: one for the Songs element, one for each Song element, and one for each Genre. The template for the Songs element looks like this (in pseudocode):
 <xsl:template match="Songs">
  <table width="100%">
    <xsl:apply-templates select="Song" />
Notice where it uses <xsl:apply-templates>. This is where someone else may use <xsl:for-each>. As in, "for each song, output the following HTML". xsl:for-each lends itself to a small number of monolithic templates, rather than a larger number of small (and re-usable) templates. In my version, it says "apply the songs template for each Song element". It's almost the same thing but with a separate Song template, we can re-use it in another template or even another XML document. And if you want to change how the Song is displayed, it's easier to zero in on its template without wading through the Songs template.

A similar argument goes for displaying Genres within the Song template:
 <xsl:template match="Song">
   <td><xsl:value-of select="SongTitle" /></td>
   <td><xsl:value-of select="Artist" /></td>
   <td><xsl:apply-templates select="Genre" /></td>

In this case, we output a single table row for each song. The list of genres will appear in a single table cell in some form (e.g. an unordered list or a comma-delimited list). Again, we keep the focus on the song, and not the extraneous stuff. An argument could be made here that Genre is insignificant enough that it could be included using xsl:for-each. I'll listen to that argument but still prefer to use templates for the most part.

The root template
In many XSL documents, I'll see a template like this: <xsl:template match="/">. To me, this obviously matches the root element of the XML and is the template that triggers the whole thing.

Maybe it's my compulsive nature but I prefer not to use "/" in a template. In reality, it says, "apply this template to every element no matter what it is". The only thing that keeps it from rendering every element in your DOM is careful (and in many case, lucky) use of <xsl:apply-templates> elsewhere in your document. When you use <xsl:apply-templates>, it will find the template that most closely matches your select attribute. In my above example, <xsl:apply-templates select="Song" /> will look for a template that specifically matches Song. If one isn't found, it will use the one that matches "/" (provided no other less general templates exist).

This seems dangerous to me even if it usually doesn't turn out that way in practice. But if you know your root node is named "Songs", why not include a template that specifically matches "Songs"? It's more consistent with the rest of your templates and avoids any accidental use of the default template. Which is how it should be used: as a default template. I.E. If no other templates match, use this as the default template. Useful for formatting individual text the way you like it without having to create a template for every node.

Default namespaces
XSL doesn't like 'em. Well, that's not totally true. XSL can deal with them just fine. But you may not be able to deal with how XSL uses them.

Say our Songs.xml file uses a default namespace: xmlns="http://www.suvius.com". This means that every node in the XML will be qualified with that namespace (if it isn't already explicitly qualified with another one). So when I say <xsl:apply-templates select="Song" />, XSL won't find any nodes. In this case, it's looking for unqualified Song nodes, which don't exist. The end result is that your transformation will show a whole lot of white space when you're expecting HTML.

To do this properly, you need to add that default namespace to your XSL...but not as a default namespace itself. Using the same default namespace mentioned in the previous paragraphy, I would add the following to the <xsl:stylesheet> element: xmlns:suvius="http://www.suvius.com". That is, the default namespace in the XML document is a named namespace in the XSL document.

Now, when I want to apply a template or reference a node, it'll look like this: <xsl:apply-templates select="suvius:Song" />.

Consider namespaces to be a substitution. I.E. XSL will replace the namespace with its contents. If a default namespace is used, all unqualified nodes in the XML will have that namespace prepended to it. So my Song node in the XML document is processed as if it looks like this: http://www.suvius.com:Song.

By adding a named namespace to the XSL, I would reference this node in the XSL document using suvius:Song, which the parser would convert to http://www.suvius.com:Song, thus matching the node in the original XML document.

A lot of work, to be sure. And the best way around this is: don't use default namespaces. Easier said than done when using web services. When you specify a namespace on a web service, it will be converted to a default namespace when the object being returned is serialized to XML. Depending on your needs, you can specify a blank namespace in your web service, which means no default namespace will be used. This might raise other concerns, though, especially if it is a public service.

This post was auto-generated by my fingers.