8 January 2010

CSS is a special case of XSLT

Many developers new to XSLT struggle to get to grips with the processing model. As a result, it seems to have a terrible reputation. However, for the job it was designed for (i.e. transforming hierarchical data structures from one representation to another), I have yet to find a more satisfactory approach (this, despite my enthusiasm for languages like Lisp and Haskell -- if you're stuck with Java, the use of XSLT is even more compelling).

This is at odds with the reputation of CSS. Sure CSS has it's detractors but most people recognise that it's the best option for adding style information to an HTML document. If you already know CSS though, then you're almost there with XSLT. Thinking about their similarities may also help XSLT developers think about CSS.

The CSS rules you define in a stylesheet boil down to a transformation engine that operates on the associated HTML document. The output is another HTML document where all the style information has been filled in for each node in the document according to the rules you've defined in the stylesheet.

CSS rules consist of a set of selectors and for each selector, a rule body containing a list of assignments. For example the CSS fragment below, the selector is "div.post", and the rule body is the rest.

div.post {
  background-color: white;
  font-family: Verdana;
}

If we consider how we'd create the same transformation engine in XSLT, it becomes obvious that the CSS version is a simplified version of the equivalent XSLT code.

<xsl:template match="div[@class='post']">
  <xsl:copy>
    <xsl:attribute name="style">
      background-color: white;
      font-family: Verdana;
    </xsl:attribute>
  </xsl:copy>
</xsl:template match>

On the one hand, the XSLT code is a little more verbose but on the other, XSLT allows your input/output to be any type of XML document (rather than just HTML), and the @match and @select expressions can be more complicated. Also, with XSLT 2, you can package up repeating patterns and/or complicated @selects as functions.