Listing 1 TableUtils.js
var currentRow = null;
var currentSortBy = null;

function transformTableData(){
oXMLDOM = document.all.XMLdata.XMLDocument;
oXSLDOM = document.all.tableXSL.XMLDocument;
newHTML = oXMLDOM.transformNode(oXSLDOM);
document.all.tableBody.innerHTML = newHTML;
}

function sort(sortBy,dataType){
XSLIsland = document.all.tableXSL.XMLDocument;
var objSelect =
XSLIsland.selectSingleNode("//xsl:sort/@select");

objSelect.nodeValue = sortBy;

var objOrder =
XSLIsland.selectSingleNode("//xsl:sort/@order");
if (currentSortBy == sortBy){
if (objOrder.nodeValue == "ascending") {
objOrder.nodeValue = "descending";
} else {
objOrder.nodeValue = "ascending";
}
} else {
objOrder.nodeValue = "ascending";
}
currentSortBy = sortBy;
var objDataType =
XSLIsland.selectSingleNode("//xsl:sort/@datatype");
objDataType.nodeValue = dataType;
transformTableData();

selectRow(document.getElementsByTagName('TR').item(1));
}
function keyCheck(keyCode){
switch (keyCode)
{
//enter
case 13:
selectCurrentRow();
break;
//up arrow
case 38:
try{
selectRow(currentRow.previousSibling);
} catch(e){}
break; //down arrow
case 40:
try{
selectRow(currentRow.nextSibling);
} catch(e){}
break;
}
}
function selectRow(row){
if(row == null){
try{
currentRow.style.backgroundColor = "#ccffff";
} catch(e){}
try{
currentRow.nextSibling.style.backgroundColor = "#ffffff";
} catch(e){}
try{
currentRow.previousSibling.style.backgroundColor =
"#ffffff";
} catch(e){}
} else {

try{
row.style.backgroundColor = "#ccffff";
} catch(e){}
try{
currentRow.style.backgroundColor = "#ffffff";
} catch(e){}
parent.currentRow = row;
currentRow = row;
}
}

function selectCurrentRow(){
XMLIsland = document.all.XMLdata.XMLDocument;
alert("You selected " + XMLIsland.selectSingleNode
("//row[@id='" + currentRow.childNodes(0)
.innerText + "']").xml);
}

Listing 2 Table.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">

<TABLE width="775" border="1" cellspacing="0"
bgcolor="white">
<xsl:for-each select="//row">
<xsl:sort select="./@lastname" order="ascending"
datatype="text" case-order="lower-first"/>
<TR id="trnode">
<xsl:attribute name="onclick">selectRow(this)
</xsl:attribute>
<xsl:attribute name="ondblclick">
selectRow(this);selectCurrentRow()
</xsl:attribute>
<TD style="display:none">
<xsl:value-of select="./@id"/>
</TD>
<TD id="lastnameCol" width="125">
<xsl:value-of select="./@lastname"/>
</TD>
<TD width="100">
<xsl:value-of select="./@firstname"/>
</TD>
<TD width="100">
<xsl:value-of select="./@phone"/>
</TD>
<TD width="75">
<xsl:value-of select="./@birthdate"/>
</TD>
<TD id="accountCol" width="200">
<xsl:value-of select="./@account"/>
</TD>
<TD width="100">
<xsl:value-of select="./@city"/>
</TD>
<TD width="75">
<xsl:value-of select="./@state"/>
</TD>
</TR>
</xsl:for-each>
</TABLE>
</xsl:template>
</xsl:stylesheet>

Listing 3 SortableTable.html
<SCRIPT src="TableUtils.js"></SCRIPT>
<SCRIPT>
function initializeTable(){
currentSortBy = "./@lastname";
transformTableData();
// select first row in the table
selectRow(
document.getElementsByTagName('TR').item(1));
}
</SCRIPT>
<HTML>
<STYLE>
TH{background-color:#006699;
color:white;cursor:hand;}
</STYLE>
<BODY onload="initializeTable()"
onkeydown="keyCheck(event.keyCode);">
<DIV id="tableHeader">
<TABLE width="775" border="1" cellspacing="0">
<TR>
<TH width="125" onClick="sort('./@lastname','text');">
LastName
</TH>
<TH width="100" onClick="sort('./@firstname','text');">
FirstName
</TH>
<TH width="100" onClick="sort('./@phone','number');">
Phone
</TH>
<TH width="75" onClick="sort('./@sortdate','number');">
Birthday
</TH>
<TH width="200" onClick="sort('./@account','text');">
Account
</TH>
<TH width="100" onClick="sort('./@city','text');">
City
<TH width="75" onClick="sort('./@state','text');">
State
</TH>
</TR>
</TABLE>
</DIV>

<DIV id="tableBody"
style="width:775px;height:100px;overflow:scroll;">
</DIV>
<XML id="tableXSL" src="Table.xsl">
<XML id="XMLdata" src="XMLData.xml">

Listing 4 XMLData.xml
<?xml version="1.0"?>
<rows>

<row id="1234" lastname="Geller"
firstname="Andrew" phone="800-555-1234"
birthdate="10/02/1952" sortdate="19521002"
account="123456" city="Albany" state="NY"/>
<row id="7622" lastname="Lincoln"
firstname="Abe" phone="800-123-5643"
birthdate="08/05/1954" sortdate="19540805"
account="637663" city="Miami" state="FL"/>
<row id="3434" lastname="vanStueben"
firstname="William" phone="888-555-3213"
birthdate="02/02/1946" sortdate="19460202"
account="123456" city="Denver" state="CO"/>
<row id="3132" lastname="VanStueben"
firstname="Robert" phone="888-555-0000"
birthdate="02/28/1926" sortdate="19260228"
account="031233" city="Austin" state="TX"/>
</rows>

Additional Code for this Article