Apply XSLT style sheet to an XML document for browser friendly display

As posted posted previously I’m doing quite a lot of work with XML these days. As part of the process I’m writing XSLT style sheets to make sure the XML documents displays nicely in the browser if the user decides to open the XML document directly in the browser. Doing so is surprisingly simple.

A practical example of linking a style sheet to an XML document is used in many RSS/ATOM feeds to let the user know what is they opened and how they should really handle the feed.

Suppose you have a XML document describing a traceroute as shown below. What you really want is for the user to see a HTML table summarizing the traceroute command in the browser instead of the barebones DOM tree. To do so you only need to add a <?xml-stylesheet /> tag at the top of the XML document with the URL to a XSLT style sheet.

Below you can see an example of an XML document with an embedded <?xml-stylesheet /> tag, the XSLT style sheet and the HTML table that results from the transformation.

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="traceroute.xsl" type="text/xsl"?>
<traceRoute target="yahoo.com" hostAddress="66.94.234.13"
  hostName="w2.rc.vip.scd.yahoo.com" initiated="2006-05-17T09:46:18.378"
  completed="2006-05-17T09:46:25.668">

  <hop hopNumber="1" hostAddress="192.168.1.1"
    hostName="192.168.1.1">
    <timing responseReceived="true" roundTripTime="2" />
    <timing responseReceived="true" roundTripTime="1" />
    <timing responseReceived="true" roundTripTime="1" />
  </hop>
  <hop hopNumber="2" hostAddress="80.243.112.1"
    hostName="1.112.243.80.vl20-cph.dhcp.clearwire.dk">
    <timing responseReceived="true" roundTripTime="28" />
    <timing responseReceived="true" roundTripTime="67" />
    <timing responseReceived="true" roundTripTime="33" />
  </hop>
  <hop hopNumber="3" hostAddress="208.49.181.237"
    hostName="ge-1-1-0.400.br1.CPH1.gblx.net">
    <timing responseReceived="true" roundTripTime="37" />
    <timing responseReceived="true" roundTripTime="58" />
    <timing responseReceived="true" roundTripTime="39" />
  </hop>
  <hop hopNumber="4" hostAddress="67.17.64.69"
    hostName="so7-2-0-2488M.ar1.DCA3.gblx.net">
    <timing responseReceived="true" roundTripTime="220" />
    <timing responseReceived="true" roundTripTime="156" />
    <timing responseReceived="true" roundTripTime="117" />
  </hop>
  <hop hopNumber="5" hostAddress="208.51.74.182"
    hostName="yahoo-2.ar1.DCA3.gblx.net">
    <timing responseReceived="true" roundTripTime="115" />
    <timing responseReceived="true" roundTripTime="121" />
    <timing responseReceived="true" roundTripTime="142" />
  </hop>
  <hop hopNumber="6" hostAddress="216.115.101.130"
    hostName="so-3-1-0.pat2.pao.yahoo.com">
    <timing responseReceived="true" roundTripTime="234" />
    <timing responseReceived="true" roundTripTime="193" />
    <timing responseReceived="true" roundTripTime="195" />
  </hop>
  <hop hopNumber="7" hostAddress="216.115.106.181"
    hostName="ge-3-0-0-p250.msr2.scd.yahoo.com">
    <timing responseReceived="true" roundTripTime="189" />
    <timing responseReceived="true" roundTripTime="185" />
    <timing responseReceived="true" roundTripTime="187" />
  </hop>
  <hop hopNumber="8" hostAddress="66.218.82.219"
    hostName="ten-1-3-bas2.scd.yahoo.com">
    <timing responseReceived="true" roundTripTime="210" />
    <timing responseReceived="true" roundTripTime="206" />
    <timing responseReceived="true" roundTripTime="201" />
  </hop>
  <hop hopNumber="9" hostAddress="66.94.234.13"
    hostName="w2.rc.vip.scd.yahoo.com">
    <timing responseReceived="true" roundTripTime="186" />
    <timing responseReceived="true" roundTripTime="184" />
    <timing responseReceived="true" roundTripTime="210" />
  </hop>
</traceRoute>

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

  <xsl:template match="/traceRoute">
    <html>
    <body>
    <table border="1">
    <xsl:for-each select="//hop">
      <tr>
      <td>
      <xsl:value-of select="@hopNumber" />
      </td>
      <td>
      <xsl:value-of select="@hostAddress" />
      </td>
      <td>
      <xsl:value-of select="@hostName" />
      </td>
      </tr>
    </xsl:for-each>
    </table>
    </body>
    </html>
    </xsl:template>
</xsl:stylesheet>

1 192.168.1.1 192.168.1.1
2 80.243.112.1 1.112.243.80.vl20-cph.dhcp.clearwire.dk
3 208.49.181.237 ge-1-1-0.400.br1.CPH1.gblx.net
4 67.17.64.69 so7-2-0-2488M.ar1.DCA3.gblx.net
5 208.51.74.182 yahoo-2.ar1.DCA3.gblx.net
6 216.115.101.130 so-3-1-0.pat2.pao.yahoo.com
7 216.115.106.181 ge-3-0-0-p250.msr2.scd.yahoo.com
8 66.218.82.219 ten-1-3-bas2.scd.yahoo.com
9 66.94.234.13 w2.rc.vip.scd.yahoo.com