Do you want to incorporate a method of sorting a table display in your XML or Extensible Style Language (XSL) documents? This task isn't difficult, but let me offer a couple of tips and a gotcha.

For the sort routine, just use your favorite scripting language. In this example, I use JavaScript. Excluding all error-checking code, the sort routine boils down to:

<xsl:script language="JavaScript">
    <!\[CDATA\[
                function sort(field)
                \{
                        //Get the order-by attribute node
                        var sortField = stylesheet.selectSingleNode("//@order-by");
                        //If the field passed in is the same as the one it's set
                to, then //reverse the sort
                sortField.value = (sortField.value == field) ? '-'+field : field;

        //Transform the XML and dump it into the HTML element
        document.all.resultListing.innerHTML =
sourceXML.transformNode(stylesheet);
        \}
        \]\]>
</xsl:script>

To make this code work, you need to load your stylesheet and source XML document into a Document Object Model (DOM). You can load these in the window.onload() event, in which case they would display immediately in the viewer. Or, the stylesheet and source XML document can load in response to a user event such as clicking a refresh button. Also, this routine assumes that you have only one node with an order-by attribute in your stylesheet. In my stylesheet, I have

<xsl:for-each select="//rs:data/z:row’ order-by="recordID">

around the code to build the <TH> and <TD> rows. If you have more than one node with this order-by attribute, then you need to have a more sophisticated XPath search string or code to return the order-by attribute node. To activate this code, simply include it in the code that builds the <TH> elements. For example, if you have a column that displays the recordID attribute, use the following HTML:

<TH onclick="sort('recordID')">ID</TH>

Notice that I used the attribute recordID, but I don’t include the @ character in front of the attribute name. You might think that the syntax for this routine should be "sort('@recordID')", but this is where my tips come in.

I haven't seen the first tip documented anywhere, but it works great. If you want to sort information in the table numerically by recordID instead of doing a character-based sort and the attribute is defined in the schema as "dt:type='ID'", then leave off the @ character. This method gives you records sorted as 1, 2, 3, 4, and so on, instead of 1, 10, 11, 2, 20, 21, and so on.

The second tip concerns the code to reverse the sorting order. If you use the sort() function to transform the data, then you might want to call the function to refresh the display if underlying data has changed rather than writing a different routine that does the same thing. Because you use the sort() function to transform the XML, you can also call the sort() function to do a transformation but leave the sort order unchanged. Because the code checks to see whether you're sorting by the same field—and if so, reverses the sort—simply get the current sort value, set the sort value to an empty string, and call the sort() function with the original sort value. This method will leave the sort unchanged but execute the XML transformation.

Now, here's the gotcha. If you include the sort() function in your XSL, make sure that you bracket it with CDATA, as I did in the example above. If you don't, and your function includes characters that have special meaning to XSL, such as "<" or "/", then the XSL processor will choke and you'll wonder why in the world an XSL debugger isn't available. You can download the complete source code for this example from http://www.interknowlogy.com/resources/support.asp.