I like XSLT. Although if you’ve ever visited my codeflood website and had a look at my SashimiCMS you’d have guessed that. SashimiCMS is a CMS I created many years ago, all based on XML and XSLT. In fact, I currently use that CMS to manage codeflood.
XSLT is a great tool for working with XML and transforming it. So it’s always a shame when I see Sitecore projects that avoid XSLT (renderings). XSLT can be quite foreign for C# developers. This is because unlike C# which is considered procedural (do this, then to this, then do this), XSLT is declarative (when this happens do this, when this happens do this, when this happens do this). It’s a very different mindset to get into. But once you tap it correctly, it’s quite powerful, for the right problem. XSLT is a very specific language and was never designed to do all things, which is why at times we need to drop out to extensions (C# methods) to get stuff done.
What it comes down to is, use the right tool for the right job. Use XSLTs for their strength, which is processing XML. Yes you could do it in C# code, but it may be more complicated than if you take the pill and use XSLT instead. Especially when working on hierarchical data.
This post is going to cover a few points to writing “good” XSLT stylesheets and make the maintainable. Let’s first take a look at how we can reuse common xsl:templates across multiple files. And no, copy/paste inheritance is not the answer.
xsl:include allow you to extract common templates to a separate file and reuse them. So what’s the difference between
xsl:include? Just the importance of the templates that are brought in from the external file. When you use
xsl:include, it’s as if the templates from the external file existed within the current file, so the included templates have the same importance as the templates of the current file. When you use
xsl:import, the imported templates have less importance than the current file’s templates. If the imported file had a template the same as the current file, the current file template would be used, but if
xsl:include was used the transform engine would throw an error that it saw two templates that match with the same importance.
Let’s take a look at an example of extracting common templates.
Let’s create a new XSLT file called
DataUtil.xslt that contains the following code:
The above code contains a single
xsl:template used to render the title of a Sitecore item. If the title field is empty it will fallback to use the item’s name instead.
Note how I’ve missed all that normal Sitecore boilerplate? That’s because this file is not a Sitecore rendering. I don’t intend to use it directly but instead it will be included in other renderings.
Now let’s create a new Sitecore rendering which includes the
DataUtil.xslt common templates.
By extracting common
xsl:templates such as the one above, we’ve allowed those templates to be reused in any other
xsl:template and gained all the benefits of sharing a common piece of code between multiple files:
- Code using the common templates will be more consistent as they don’t have to rewrite the same code.
- Maintenance of the code is much easier as it only exists in a single file.
The above code is only one example of a common
xsl:template. I bet you could come up with a number of these just by looking through your current project, such as creating a link to an item (output the item title if supplied, otherwise just output the item name).
On the projects I do see using XSLT in Sitecore, it’s not often I see a good structure or technical design for the XSLT. How often have you seen this kind of rendering in Sitecore?
Sitecore provides a nice starting point for renderings but many developers don’t extend beyond that very well.
A good XSLT will make appropriate use of
xsl:templates to process different elements of input, in the same fashion as a good C# class will make appropriate use of methods to break apart complex processing tasks.
For example, let’s consider the following XSLT which is used to generate a simple menu from the Sitecore content tree (single level).
This code could be made better by splitting out the part that renders the link, from the part that walks the content tree.
<xsl:template match="*" mode="main">
In the above code we’ve split the link generation out to it’s own
xsl:template. This makes the code easier to understand, but also makes it easier to reuse and override.
Let’s say we now have a new requirement on a project for a new kind of menu control. It should traverse the content tree in the same way as the above menu, but instead of outputting simple links it should wrap each link in a
div and a
span (to allow appropriate styling through CSS). There are two approaches you could take to satisfy this new requirement while leveraging the existing control (and hence, reducing the amount of effort required to deliver the requirement).
Firstly, let’s add some parameters to the XSLT to allow specifying whether the link should be wrapped and by what.
<xsl:param name="wrap1" select="'div'" />
And now to update the
xsl:template to output the required tags when the parameters are used.
Looks kind of messy right? And I’m not too sure about manually generating tags through textual output (rather than just specifying the tag directly).
A cleaner approach is to create a new rendering, but make use of the existing XSLT and override the
xsl:templates that need to change.
Note above how we’ve used
xsl:import so the templates defined in the XSLT will take priority over those in the imported file. And because we’re making use of the
Simple Menu.xslt from above, we don’t need to specify templates that don’t change in this file, such as the default Sitecore provided main mode template or the content tree traversal template.
The above code does the same as the first revision, but I think it looks much cleaner. By splitting the piece of code that generates the link out to a separate template it’s much easier to override the
renderLink template and adjust the output per link. This is the same kind of benefit we gain when using inheritance in C# to override specific methods.
I hope this post will make you think carefully about the structure of your
xsl:templates next time you’re creating an XSLT. And if you don’t use renderings in your Sitecore projects I hope this motivates you to give them a go.