AjaxPatterns
This is the original book draft version for the Browser-Side XSLT Ajax pattern, offered for historical purposes and as an anti-spam measure.
You're probably better off visiting the Live Wiki Version for Browser-Side XSLT instead, where you can make changes and see what others have written.

Browser-Side XSLT

Presentation, Render, Style, Stylesheet, Transform, View, XML, XPath, XSLT

Developer Story

Dave has just received a request to change the weather portlet on the homepage. The image must now be on the bottom, not the top, and the wording should be more precise. The browser receives periodic weather updates in the form of an XML specification and uses Browser-Side XSLT to get HTML for the portlet. The stylesheet is embedded inside the static homepage HTML file. So Dave just has to tweak the XSLT to get all the browsers rendering the new design.

Problem

How can you render incoming XML?

Forces

  • Many “Web Service”s output “XML Message” and Ajax clients have to convert them into HTML.

  • While modern browsers provide good support for XML parsing via the Javascript's DOM support, the direct interface is lengthy and tedious to use.

  • Code gets complex and error-prone when you mix HTML generation with application logic. Javascript is not well-suited to programmatically building up HTML strings from input XML.

Solution

Apply XSLT to convert “XML Message”s into XHTML. XSLT - Extensible Stylesheet Language Transformations - is a language for transforming XML documents into other forms. Here, XML is transformed to XHTML, a type of HTML that conforms to the XML standard. (You could get away with converting to plain-old HTML, but things works better if you stick to XHTML.) XSLT is fairly well-supported in modern browsers and, although browser APIs vary, there are good cross-browser toolkits available.

XSLT is well-suited to rendering XML. An XML document is designed to encapsulate a data object, and an XSLT stylesheet is a strategy for presenting such objects. Previously, XSLT has been used as a server-side technology - the server grabs some XML from a repository or another process and creates a web page by transforming it into XHTML. All that happens on the server. More recently, browsers have incorporated XSLT functionality, so the browser can automatically create an HTML page by marrying together an XML document with an XSLT stylesheet.

Browser-Side XSLT is slightly different. Here, the XML document does not constitute the contents of the entire page, but a response from an “XMLHttpRequest Call”. The transformation to XHTML can take advantage of the browser's built-in XSLT support, or alternatively an XSLT processor can be implemented in Javascript, building on the browser's more primitive XML features. However the XSLT occurs, you're unlikely to be implementing it yourself. There are a couple of good cross-browser libraries available, discussed in the Real-World Examples below.

It's beyond the scope of this pattern to explain XSLT in any detail; however, here's a quick overview:

  • An XSLT stylesheet is itself an XML document.

  • An XSLT processor transforms an XML document into another form, by parsing the original document and using the stylesheet as the transformation strategy.

  • XSLT expressions are specified in another language, XPath. Among its capabilities, XPath provides a powerful mechanism for expressing a position within an XML document. For example, the XPath expression /category/items/category will match twice when the following document is processed:

        <category>
          <items>
            <category name="popular">
              <!-- XPath expression matches this category node -->
              ...
            </category>
            <category name="extras">
              <!-- XPath expression matches this category node -->
              ...
            </category>
          </items>
        </category>
    

  • A stylesheet is composed of rules. Each rule has a pattern that defines when it applies, and a template that dictates what will be output each time the pattern is encountered. Continuing with the example, here's a full rule:

        <xsl:template match="/category/items/category">
            <div class="category"
                 onclick="retrieveCategory('{@name}')">
                 <xsl:value-of select="@name"/>
            </div>
        </xsl:template>
    

    When each node is reached, the template is outputted. @name refers to the name attribute on the category tag. So when the processing engine reaches the following XML segment:

        <category name="extras">
    

    the following XHTML will be output:

        <div class="category"
             onclick="retrieveCategory('{extras}')">
             <xsl:value-of select="extras"/>
        </div>
    

This discussion has focused on the most obvious application of Browser-Side XSLT: conversion to HTML for display to the user. You can also convert the XML to Javascript too, and then execute it with the eval() method. For example, it would be possible to build a native Javascript object by converting some XML into some code that creates the object.

Decisions

How will you obtain the XSLT stylesheet?

Any Browser-Side XSLT processor requires two things:

  • An XML document.

  • An XSLT stylesheet.

Both are usually passed in to the XSLT processor as plain strings representing the entire document (as opposed to URLs, say). The XML document usually comes from an “XMLHttpRequest Call”, but where does the XSLT stylesheet come from? You have a few options:

Store the stylesheet server-side

You can hold the file server-side, and then use independent “XMLHttpRequest Call” to retrieve it. In this case, you'll probably want to keep the copy in a “Browser-Side Cache” for later use. Also, if you use an asynchronous call, which is advisable, there's a potential race condition: you need to ensure the stylesheet is retrieved before any transformation takes place, possibly with a loop that keeps checking for it. The Refactoring Illustration below demonstrates this approach.

Hand-code the stylesheet as a Javascript string

You can build up a string in Javascript, though this leads to messy code which blurs the distinction between logic and presentation. There is one benefit of this approach: the stylesheet is dynamic, so could potentially vary according to the current context.

Store it inside the initial HTML document

You can tuck the stylesheet somewhere inside the initial HTML document where it won't be seen by the user. Techniques include:

Real-World Examples

Google Maps

Google Maps is the most famous application of Browser-Side XSLT, where the technology is used to transform data such as addresses and coordinates into HTML. Based on this work, the Googlers have also released Google AJAXSLT, an open-source framework for cross-browser XSLT and XPath.

Kupu

Kupu is an online word processor which stores content in XML and renders it using Browser-Side XSLT, using the Sarissa framework described below (Figure 1.33, “Kupu Word-Processor”).

Figure 1.33. Kupu Word-Processor

Kupu Word-Processor

Ajax-S

Robert Nyman's AJAX-S is a slideshow manager, where raw content is maintained in XML, and transformed to slides using Browser-Side XSLT.

Sarissa Framework

Sarissa is an open-source, cross-browser, framework for all things XML. XSLT is supported as well as XML parsing, XPath queries, and XMLHttpRequest invocation.

Code Refactoring [AjaxPatterns XSLT Drilldown Demo]

This refactoring is similar to that performed in “Browser-Side Templating”, but using XSLT instead of templating. The starting point, the Basic Drilldown Demo, converts XML to HTML using a series of Javascript string concatenations. The callback function, which receives the XML, therefore performs lots of string concatenations as follows:

    html+="<div id='categoryName'>" + categoryName + "</div>";

In this refactoring, all that string-handling is replaced by an XSLT transformation, using the Sarissa library. One slight complication is the stylesheet - how does the script access it? The solution here is to keep it as a separate file on the server and pull it down on page load:

    var xsltDoc;
    window.onload = function() {
      ...
      ajaxCaller.getXML("./drilldown.xsl",function(response) {xsltDoc = response;});
      ...
    }

As was mentioned in the Decisions above, there's a race condition here, because the XML response may come before the stylesheet. To deal with this, the drilldown callback function keeps looping until the stylesheet is defined:

    function onDrilldownResponse(xml) {
      if (xsltDoc==null) {
        setTimeout(function() { onDrilldownResponse(xml); }, 1000);
        return;
      }
      ...
    }

Beyond that, the callback function is simply an invocation of Sarissa's XSLT processor:

    function onDrilldownResponse(xml) {
      ...
      var xsltProc  = new XSLTProcessor();
      xsltProc.importStylesheet(xsltDoc);
      var htmlDoc = xsltProc.transformToDocument(xml);
      var htmlString = Sarissa.serialize(htmlDoc);
      $("drilldown").innerHTML = htmlString;
    }

The only thing left is the stylesheet itself, shown below. I'll spare a walkthrough. The output here is the same as that in the Basic Drilldown Demo, which generates the HTML using manual Javascript processing.

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="/">
        <html>
          <body>
            <xsl:apply-templates/>
          </body>
        </html>
      </xsl:template>

      <xsl:template match="/category">
        <div id='categoryName'><xsl:value-of select="@name" /></div>
        <xsl:if test="@parent!=''">
          <div id='parent' onclick='retrieveCategory("{@parent}")'>
            Back to <xsl:value-of select="@parent" />
          </div>
        </xsl:if>
        <xsl:apply-templates/>
      </xsl:template>

      <xsl:template match="/category/items/link">
        <div class="link"><a href="{url}"><xsl:value-of select=
"name"/></a></div>
      </xsl:template>

      <xsl:template match="/category/items/category">
          <div class="category"
               onclick="retrieveCategory('{@name}')">
               <xsl:value-of select="@name"/>
          </div>
      </xsl:template>

    </xsl:stylesheet>

Alternatives

Browser-Side Templating

Browser-Side Templating is a solution for rendering content in any fformat - plain text, XML, and so on. You could extract key variables from an “XML Message” and render them with a templating engine. “Browser-Side Templating” is a simpler approach as it builds on existing Javascript knowledge, while Browser-Side XSLT allows for more powerful transformations and avoids the cumbersome querying of XML in Javascript.

Related Patterns

Browser-Side XSLT is driven by the need to deal with incoming “XML Message”s.

Browser-Side XSLT can be used to render an element contained in an “XML Data Island”. Also, “XML Data Island” is a good place to stick an XSLT stylesheet.

Metaphor

Browser-Side XSLT is a strategy for presenting abstract data in a human-readable form. People do this all the time with diagrams. For instance, a family tree is one way to render the abstract set of relationships in a family. A UML diagram is a visual representation of some (real or imagined) code.

Live Wiki Version for Browser-Side XSLT