How to Transform XML into Dynamic HTML

You know what I like about XML? The tools. It's not "you could write a program to do that," but "there's a standard tool to do that." Generating XML is really easy, and once get your data into XML format, you can do quite a bit with it. You might even want to look at it; that what this essay is about.

Of course, you can look XML directly from a browser; IE, for example, gives you a neat little expand/collapse view. But I'm thinking of something a little easier on the eyes. The most basic option is to style the XML directly with CSS. The problem with that is we end up with a static document. Such documents tend to have a lot of data — more than we want to scroll through. At the very least, I'd like to be able to expand and collapse sections and hyperlink related ideas.

The solution I came up with is to map to DHTML, and build the expand/collapse behavior in JavaScript. To get from XML to DHTML, we use XSLT. This is starting to seem like alphabet soup, but it's really easy, I promise. The reason it's simple is that the CSS, XSLT, and JavaScript are loosely coupled, so we can work on them separately.

Take a look at the example page, and click on each section to open it:

Example: Karen's Wonderful Recipes

(This example has only been tested in Internet Explorer. I'm too lazy to strive for cross-browser compatability in prototype/sample code.) Here are the source files:

All the JavaScript is contained in HTML generated by the XSLT, because there are calls to the functions scattered throughout the HTML. To keep JavaScript decoupled, you place it in a separate file and write code to loop over the document, registering the event handlers. (I haven't done that here, though.)

I want to point out a couple of things: the little toggle auto-open turns on a feature that expands sections when you mouse-over, which is interesting but annoying. Also note that the index at the top is sorted in alphabetical order; I'll talk about that in detail later.

The XML Data

Let's first take a look at recipes.xml. It has a simple structure: a <document> contains <section>s which contain <subsections>s, and there's a generic list structure which is an <indexcard> element containing <line>s. Each section basically looks this:

<section header="Never Fail Pie Crust">
   <indexcard header="Ingredients">
      <line>  1 cup flour</line>
      <line>    1/2 cup shortening</line>
      <line>    1/2 tsp. salt</line>
      <line>    ?- 1/4 cup water</line>
   </indexcard>
   <subsection header="Instructions">
      Mix flour, shortening, and salt together until crumbly. Add water, a 
      small amount at a time until malleable. Roll out on lightly floured
      pastry cloth.
   </subsection>
 </section>

That just gives us some structure to work with; it's not important. What is important is this magic line at the top of the file:

<?xml-stylesheet type="text/xsl" href="sections.xsl"?>

(Hey wait a minute! I don't see it! That's becuase I took that line out of the link to source, so the transformation wouldn't be applied. Click 'view source' on the example to see it.)

That's a processing directive. It tells a browser apply the XSL Transformation from sections.xsl. You'll have to delete or ignore this directive when parsing the XML with other tools, but that's the only way to tell the browser what to do.

The XSLT File

The XSLT file has some magic too:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="ISO-8859-1"/>
  .
  .
  .
</xsl:stylesheet>

That's boilerplate, and just says this is a XSLT transformation going to HTML. A style sheet is mostly made of templates:

<xsl:template match="indexcard/line">
      <li>
       <xsl:apply-templates />
      </li>
</xsl:template>

That says, "every time you see a <line> element inside an <indexcard> element, turn it into an HTML <li> element. If you want to include the value of an XML attribute, you do this:

<xsl:value-of select="@header" />

The example file also shows you how to build a link dynamically:

<a>
  <xsl:attribute name="href">#<xsl:value-of select="@header" /></xsl:attribute>
  <xsl:value-of select="@header" />
</a>

That's cool, because it lets us build a sophisticated linking structure directly from the XML. Also note this bit of magic for escaping non-XML entities :

<xsl:text disable-output-escaping="yes">&amp;darr;</xsl:text>

This results in the entity &darr; being included in the HTML. You don't have to worry about this right away, but you will need it eventually. Note that Firefox has a problem with this; you should use numerical entities instead if you're striving for cross browser compatability.

There's nothing special about the template that matches the <document> element, but because it gets transformed into the <html> element, that template includes the script and link to the CSS. Look carefully, though, and you'll see that is all inside a normal <xsl:template> element.

<xsl:template> and <xsl:value-of> are basically all you need. With those two, you can expand each XML element to an arbitrary presentational structure. I haven't used any tables here, but you don't need anything else. But we can go farther with XSLT, and I think that's where this technique starts to pay serious dividends.

The Index

Remember how I pointed out the index at the top of the document? There's no equivalent index structure at the top of the original XML data. Instead, the index was built with this code:

<xsl:for-each select="section">
  <xsl:sort select="@header"/>
  <a>
    <xsl:attribute name="href">#<xsl:value-of select="@header" /></xsl:attribute>
    <xsl:value-of select="@header" />
  </a>
</xsl:for-each>

We're simply looping over all the <section> elements in the <document>, sorted in alphabetical order. We could extract whatever we want for each one, but here we just make a hyperlink to that section. By the way, to make that work we included a named anchor tag before each section:

<a><xsl:attribute name="name"><xsl:value-of select="@header" /></xsl:attribute></a>

Note that the named anchor tags are placed outside the sections; I do that so the window jumps to where you can see the title. That's ok; HTML is a presentational format, and we already have a "purer" data structure in the XML.

Roll Your Own

This technique gives a classy presentation for our data: collapsing sections, automatically generated indexes and cross links, and orthogonal styling. Now that you know it's possible and have an example of how it's done, you'll be able to do it yourself without too much trouble. The XSLT used here is quite basic: the w3schools tutorial should suffice, and you may want to learn more about XPath, the notation used inside select attributes to match nodes. Coming up with the XSLT is the easy part. Styling with CSS is also easy and well known. The JavaScript is easy if you know the language. The many tutorials on the Internet are your best bet for all these standard; good luck!

If you liked this essay, you might be interested in these: [ Web Tutorial ]

by Oran Looney - June 7th 2007

Comments (0)

Leave a Comment