Using XSLT to dynamically sort HTML content

Click the column headings to change the sort options.

The web server is only accessed for the initial data load.

JavaScript modifies the XSLT sorting parameters, then transforms the XML into HTML.

Scroll down to view the source code.

HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>AJAX Test</title>
    <link href="ajax.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="ajax.js"></script>
</head>
<body onload="initialize();">
    <h1>Using XSLT to dynamically sort HTML content</h1>
    <p>Click the column headings to change the sort options.</p>
    <p>The web server is only accessed for the initial data load.</p>
    <p>JavaScript modifies the XSLT sorting parameters, then transforms the XML into HTML.</p>
    <p>Scroll down to view the source code.</p>  
    <div id="disp"></div>
</body>
</html>

CSS

body { background-color: #ffffff; color:#800080; font-family: arial, verdana, sans-serif; font-size:14px; }
a { color:#809238; font-weight:bold; text-decoration:none; }
a:hover { text-decoration:underline; }
table {	background-color: #cccccc; margin: 20px 0 40px 0; }
p { color:#000000; margin:0; }
h1 { font-size:18px; }
pre { color:#000000; }
th { padding:2px; background-color:#f0f0f0; text-align:left; }     
tr { background-color: #ffffff; }
td { padding:2px; line-height:19px; }       
.numeric { text-align:right }
.ascending { padding-left:4px; width:7px; height:7px; background: url('images/asc.gif') right no-repeat; }
.descending { padding-left:4px; width:7px; height:7px; background: url('images/desc.gif') right no-repeat; }
.nosort { padding-left:4px; width:7px; height:7px; }

JavaScript

var xslDoc;   // XSLT Document
var xmlDoc;   // XML Document
var xmlText;  // XSLT Text (for IE)
var xslText;  // XML Text (for IE)
var xmlHttpObj;
var sortKey = "title";
var sortType = "text";
var sortOrder = "ascending";

function CreateXmlHttpRequestObject()
{
    var xmlObj;
    if (window.ActiveXObject)
    {     
        try
        {
           xmlObj = new ActiveXObject("Microsoft.XMLHTTP");
        } 
        catch (e)
        {
           xmlObj = new ActiveXObject("Msxml2.XMLHTTP");
        }        
    }
    else
    {        
        xmlObj = new XMLHttpRequest();
    }        
    return xmlObj;
}

function getStyleSheet()
{
    xmlHttpObj = CreateXmlHttpRequestObject();    
    xmlHttpObj.open("GET", "ajax.xsl", false);
    xmlHttpObj.send(null);
    if (xmlHttpObj.status == 200)
    {
        xslDoc = xmlHttpObj.responseXML; 
        xslText = xmlHttpObj.responseText;
    }
    else
    { 
        alert("error loading stylesheet " + xmlHttpObj.status);
    }    
}

function getDataFile()
{
    xmlHttpObj = CreateXmlHttpRequestObject();    
    xmlHttpObj.open("GET", "ajax.xml", false);
    xmlHttpObj.send(null);
    if (xmlHttpObj.status == 200)
    {
        xmlDoc = xmlHttpObj.responseXML;
        xmlText = xmlHttpObj.responseText;
    }
    else
    {
        alert("error loading data file " + xmlHttpObj.status);
    }
}

function doTranslation()
{
    try
    {
        var processor = new XSLTProcessor();
        processor.importStylesheet(xslDoc);
        processor.setParameter(null, "sortKey", sortKey);
        processor.setParameter(null, "sortOrder", sortOrder);
        processor.setParameter(null, "sortType", sortType);
        var newDocument = processor.transformToDocument(xmlDoc);
        document.getElementById("disp").innerHTML = new XMLSerializer().serializeToString(newDocument);        
    } catch (e)
    {   
        // Load XSL
        var objXSLT = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
        objXSLT.loadXML(xslText);

        // create a compiled XSL-object
        var objCompiled = new ActiveXObject("MSXML2.XSLTemplate");
        objCompiled.stylesheet = objXSLT.documentElement;
				
        // create XSL-processor
        var objXSLProc = objCompiled.createProcessor();

        // Load your XML
        var objXML = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
        objXML.loadXML(xmlText);

        // input for XSL-processor
        objXSLProc.input = objXML;
        objXSLProc.addParameter("sortKey", sortKey);
        objXSLProc.addParameter("sortOrder", sortOrder);
        objXSLProc.addParameter("sortType", sortType);
			
        // transform
        objXSLProc.transform();

        // display
        document.getElementById("disp").innerHTML = objXSLProc.output;           
    }           
}

function reSort(which)
{
    if (sortKey == which)
    {
        sortOrder = (sortOrder == "ascending") ? "descending" : "ascending";
    }
    else
    {
        sortKey = which;        
        sortOrder = "ascending";
    }      
    sortType = (sortKey == "price" || sortKey == "year") ? "number" : "text";      
    doTranslation();
}

function initialize()
{
    getStyleSheet();
    getDataFile();
    doTranslation();
}    

XSLT

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="sortKey">title</xsl:param>
<xsl:param name="sortOrder">ascending</xsl:param>
<xsl:param name="sortType">text</xsl:param>

<xsl:template match="/">
    <table border="0" cellpadding="0" cellspacing="1">
        <tr bgcolor="#9acd32">
            <th><a href="JavaScript:reSort('title');">Title</a><xsl:call-template name="hdr"><xsl:with-param name="header" select="'title'" /></xsl:call-template></th>
            <th><a href="JavaScript:reSort('artist');">Artist</a><xsl:call-template name="hdr"><xsl:with-param name="header" select="'artist'" /></xsl:call-template></th>
            <th><a href="JavaScript:reSort('country');">Country</a><xsl:call-template name="hdr"><xsl:with-param name="header" select="'country'" /></xsl:call-template></th>
            <th><a href="JavaScript:reSort('company');">Company</a><xsl:call-template name="hdr"><xsl:with-param name="header" select="'company'" /></xsl:call-template></th>
            <th><a href="JavaScript:reSort('price');">Price</a><xsl:call-template name="hdr"><xsl:with-param name="header" select="'price'" /></xsl:call-template></th>
            <th><a href="JavaScript:reSort('year');">Year</a><xsl:call-template name="hdr"><xsl:with-param name="header" select="'year'" /></xsl:call-template></th>		 
        </tr>
    <xsl:for-each select="catalog/cd">
    <xsl:sort select="*[name(.)=$sortKey]|@*[name(.)=$sortKey]" order="{$sortOrder}" data-type="{$sortType}" />
        <tr>
            <td><xsl:value-of select="title"/></td>
            <td><xsl:value-of select="artist"/></td>
            <td><xsl:value-of select="country"/></td>
            <td><xsl:value-of select="company"/></td>
            <td class="numeric"><xsl:value-of select="format-number(price, '$#,###.00', 'currency')"/></td>
            <td class="numeric"><xsl:value-of select="year"/></td>
        </tr>
    </xsl:for-each>
    </table>
</xsl:template>

<xsl:template name="hdr">
<xsl:param name="header" />			
    <xsl:if test="$sortKey = $header">
        <xsl:if test="$sortOrder = 'ascending'"><img class="ascending" src="images/null.gif" /></xsl:if>
        <xsl:if test="$sortOrder = 'descending'"><img class="descending" src="images/null.gif" /></xsl:if>
    </xsl:if>
    <xsl:if test="$sortKey != $header"><img class="nosort" src="images/null.gif" /></xsl:if>
</xsl:template>

<xsl:decimal-format name="currency" decimal-separator="." grouping-separator=","/>

</xsl:stylesheet>

XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="ajax.xsl"?>
<catalog>
    <cd>
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Greatest Hits</title>
        <artist>Dolly Parton</artist>
        <country>USA</country>
        <company>RCA</company>
        <price>9.90</price>
        <year>1982</year>
    </cd>
    <cd>
        <title>Still got the blues</title>
        <artist>Gary Moore</artist>
        <country>UK</country>
        <company>Virgin records</company>
        <price>10.20</price>
        <year>1990</year>
    </cd>
    <cd>
        <title>Eros</title>
        <artist>Eros Ramazzotti</artist>
        <country>EU</country>
        <company>BMG</company>
        <price>9.90</price>
        <year>1997</year>
    </cd>
    <cd>
        <title>One night only</title>
        <artist>Bee Gees</artist>
        <country>UK</country>
        <company>Polydor</company>
        <price>10.90</price>
        <year>1998</year>
    </cd>
    <cd>
        <title>Sylvias Mother</title>
        <artist>Dr.Hook</artist>
        <country>UK</country>
        <company>CBS</company>
        <price>8.10</price>
        <year>1973</year>
    </cd>
    <cd>
        <title>Maggie May</title>
        <artist>Rod Stewart</artist>
        <country>UK</country>
        <company>Pickwick</company>
        <price>8.50</price>
        <year>1990</year>
    </cd>
    <cd>
        <title>Romanza</title>
        <artist>Andrea Bocelli</artist>
        <country>EU</country>
        <company>Polydor</company>
        <price>10.80</price>
        <year>1996</year>
    </cd>
    <cd>
        <title>Black angel</title>
        <artist>Savage Rose</artist>
        <country>EU</country>
        <company>Mega</company>
        <price>10.90</price>
        <year>1995</year>
    </cd>
    <cd>
        <title>For the good times</title>
        <artist>Kenny Rogers</artist>
        <country>UK</country>
        <company>Mucik Master</company>
        <price>8.70</price>
        <year>1995</year>
    </cd>
    <cd>
        <title>Big Willie style</title>
        <artist>Will Smith</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>9.90</price>
        <year>1997</year>
    </cd>
    <cd>
        <title>Tupelo Honey</title>
        <artist>Van Morrison</artist>
        <country>UK</country>
        <company>Polydor</company>
        <price>8.20</price>
        <year>1971</year>
    </cd>
    <cd>
        <title>Soulsville</title>
        <artist>Jorn Hoel</artist>
        <country>Norway</country>
        <company>WEA</company>
        <price>7.90</price>
        <year>1996</year>
    </cd>
    <cd>
        <title>The very best of</title>
        <artist>Cat Stevens</artist>
        <country>UK</country>
        <company>Island</company>
        <price>8.90</price>
        <year>1990</year>
    </cd>
    <cd>
        <title>Stop</title>
        <artist>Sam Brown</artist>
        <country>UK</country>
        <company>A and M</company>
        <price>8.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Private Dancer</title>
        <artist>Tina Turner</artist>
        <country>UK</country>
        <company>Capitol</company>
        <price>8.90</price>
        <year>1983</year>
    </cd>
    <cd>
        <title>Midt om natten</title>
        <artist>Kim Larsen</artist>
        <country>EU</country>
        <company>Medley</company>
        <price>7.80</price>
        <year>1983</year>
    </cd>
    <cd>
        <title>Pavarotti Gala Concert</title>
        <artist>Luciano Pavarotti</artist>
        <country>UK</country>
        <company>DECCA</company>
        <price>9.90</price>
        <year>1991</year>
    </cd>
    <cd>
        <title>The dock of the bay</title>
        <artist>Otis Redding</artist>
        <country>USA</country>
        <company>Atlantic</company>
        <price>7.90</price>
        <year>1987</year>
    </cd>
    <cd>
        <title>Picture book</title>
        <artist>Simply Red</artist>
        <country>EU</country>
        <company>Elektra</company>
        <price>7.20</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Red</title>
        <artist>The Communards</artist>
        <country>UK</country>
        <company>London</company>
        <price>7.80</price>
        <year>1987</year>
    </cd>
    <cd>
        <title>Unchain my heart</title>
        <artist>Joe Cocker</artist>
        <country>USA</country>
        <company>EMI</company>
        <price>8.20</price>
        <year>1987</year>
    </cd>
</catalog>