Since attending HighEdWeb 2008 and going to Jason Woodward’s Workshop on XML/XSLT, I’ve been really interested in the possibilities of using XSL to tranform a well-formed XML file into almost anything – especially another type of file, such as XHTML.
This topic is totally new to me, and I’ve never had the chance to use it in a real life scenario. I have played around a little bit with a hypothetical exercise though, and wanted to post my solution for others to use, and hopefully, offer some criticism on. Please do comment if you can think of a better or more elegant solution.
The business need
Develop a single web page that shows Henry’s current inventory. Develop a single page using XHTML standards that shows the inventory using XSL. CSS will be in the head of the XSL page and will be used to style the page. The page will show the widgets grouped by the type of metal in alphabetical order, and then the widgets in order of price with the lowest price item shown first (the list of widgets is only shown once in the page). Lastly, the out of stock widgets should be formatted differently than the ones that are in stock. Tables will be used to layout the web page.
The XML
I developed this XML a few weeks ago, and even wrote another post patting myself on the back for having authored a schema defining my widgets, but here is a snippet:
< ?xml-stylesheet type="text/xsl" href="inventory.xsl"?>
<inventory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="inventory.xsd">
<widget>
<material>Aluminium</material>
<length units="ft">1</length>
<width units="in">2</width>
<thickness units="in">.25</thickness>
<price units="USD">15.00</price>
<stockqty>25</stockqty>
</widget>
...
</inventory>
The good stuff – XSLT
I think learning XSLT was equal parts learning to understand XSL and then learning the intricacies of Xpath – especially as it relates to <xsl:apply-templates /> and matching/selecting the elements. Anyway here’s what I came up with:
<xsl :stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
</xsl><xsl :template match="/">
<html>
<head>
<title>Henry's Widget Shoppe</title>
</head>
<body>
<h2>Here's my available widgets!</h2>
<table id="Inventory">
<tr class="tableHead">
<td>Material Type</td>
<td>Length</td>
<td>Width</td>
<td>Thickness</td>
<td>Price</td>
<td>Stock Qty</td>
</tr>
<xsl :apply-templates />
</table>
</body>
</html>
</xsl>
<xsl :template match="inventory">
</xsl><xsl :for-each select="widget">
<xsl :sort select="material" order="ascending"/>
<xsl :sort select="price" data-type="number" order="ascending"/>
</xsl><xsl :choose>
</xsl><xsl :when test="stockQty>0">
<tr class="widget">
<xsl :apply-templates select="." />
</tr>
</xsl>
<xsl :otherwise>
<tr class="widget outOfStock">
<xsl :apply-templates select="." />
</tr>
</xsl>
<xsl :template match="widget">
<td class="material">
<xsl :value-of select="material"/>
</td>
<td class="length">
<xsl :value-of select="length"/>
<xsl :value-of select="length/@units"/>
</td>
<td class="width">
<xsl :value-of select="width"/>
<xsl :value-of select="width/@units"/>
</td>
<td class="thickness">
<xsl :value-of select="thickness"/>
<xsl :value-of select="thickness/@units"/>
</td>
<td class="price">
<xsl :if test="price[@units] != 'USD'">$</xsl>
<xsl :value-of select="price"/>
</td>
<td class="stockQty">
<xsl :value-of select="stockQty"/>
</td>
</xsl>
Conclusion
I did make several improvements and tried alternate strategies over the weekend, so this isn’t exactly what I first puked out. All in all, I’m very pleased with it. This was probably one of the most valuable self learning exercises I’ve yet had.
Download the source here and/or View the transformed XML here


