Author: Lindsey Simon Published: August 23, 2006 Source: XML.com (O'Reilly Media)
Overview
This article presents a datagrid component built with XSLT and JavaScript, designed for easy setup, strong performance, and minimal dependencies. The dynamic datagrid is an often cumbersome widget to set up.
The problem
Three common approaches to JavaScript widget creation:
Approach #1 — Server-side instantiation. PHP example:
$dg = new DataGrid();
$dg->columns = array( "field1", "field2", "field3" );
$dg->data = $data;
$dg->render();
Approach #2 — Browser-side instantiation through DOM creation. Using ActiveWidgets Grid:
var myCells = [
["MSFT","Microsoft Corporation", "314,571.156"],
["ORCL", "Oracle Corporation", "62,615.266"]
];
var myHeaders = ["Ticker", "Company Name", "Market Cap."];
var obj = new AW.UI.Grid;
obj.setCellText(myCells);
obj.setHeaderText(myHeaders);
obj.setColumnCount(3);
obj.setRowCount(2);
document.write(obj);
Approach #3 — Hybrid. Declarative XHTML serves as a base, then is enhanced. Like building a house: the declarative XHTML is the frame, while DOM additions are the siding, air conditioning, and champagne-filled hot tub.
var myGrid = new XSLDataGrid( 'renderDiv', { width: 480, height: 200, transformer:'client', debugging: true } );
Approach #1 lacks portability since it depends on the server language. Approach #2 fails when JavaScript is disabled and struggles with large datasets. Approach #3 is the chosen compromise.
In defense of the table tag
While CSS has rightly reduced reliance on tables for layout, the <table> family provides a declarative, semantic language for describing tabular data — handling cases where nested DIVs and floats grow unwieldy. With CSS disabled, pure DIV-based table presentation degrades poorly.
XSLT on XHTML
XSLT lets us decorate the DOM with well-formed markup in a powerful, flexible way. The transform results are inserted back via the container's innerHTML property — a technique known as AHAH.
From quirksmode.org's "Benchmark — W3C DOM vs. innerHTML":
innerHTML is faster than 'real' W3C DOM methods in all browsers. The W3C DOM table methods are slow to very slow, especially in Explorer.
The XSLDataGrid process
Semantic XHTML Table + XSLDataGrid.xsl → Decorated XHTML (more tags, attributes, CSS) + JavaScript (instantiation, event listeners) → Rich DataGrid UI in the render tree, with the original XML DOM kept in memory.
Dual-DOM, or, how I dealt with innerHTML
Three usage modes for the component:
- Fetching fully-decorated XHTML from the server each time.
- Fetching semantic XHTML from the server and transforming it client-side.
- Transforming XHTML already present on the page client-side.
For case 1, all change operations (column resize, sort, reorder) can be delegated to the server. Cases 2 and 3 require XSLT to run repeatedly, so well-formed XHTML must remain available. Internet Explorer "optimizes" innerHTML by stripping quotation marks and end tags, making round-tripping unreliable.
To work around this, on initialization the XSLDataGrid stores an XML DOM Document built from the original semantic XHTML — the "Dual-DOM" technique. For column resizing, instead of updating numerous DIVs, SPANs, THs, TDs, and COLs in the render tree, the component only changes one width attribute in the XML DOM and re-runs the XSLT.
XSLT in the browser
Both Internet Explorer and Firefox expose XSLT APIs. Manos Batsis's free Sarissa library wraps the loading of XHTML and XSL and invokes the browser's native transform method. At publication time, XSLT was not exposed to JavaScript in Safari or Konqueror, and Opera's XSLT API was not yet implemented in the XSLDataGrid.
Client-side sorting works by extracting a subset of template nodes from the XSL via DOM, then transforming the current TBODY with that subset plus parameters. The technique is limited to XSLT 1.0 datatypes — only "text" and "number." Adding "date" support via qname stylesheet templates was on the roadmap.
Benchmarks
Tests were run with the help of the Venkman profiler. Server-side tests used GNU/Linux with PHP 5.1.4; client tests used a 2GHz Pentium M running Firefox 1.5.0.6.
| Rows | Pre-XSLT (KB) | Post-XSLT (KB) | Client-side XSLT (ms) | Server-side XSLT (sec) |
|---|---|---|---|---|
| 200 | 17.5 | 29.6 | 156.25 | 0.0306 |
| 500 | 43.6 | 68.8 | 369.79 | 0.0356 |
| 1000 | 87.1 | 134 | 781.25 | 0.0860 |
| 2000 | 179.1 | 270.5 | 1684.38 | 0.2068 |
| 4000 | 363.1 | 543.5 | 3070.31 | 0.3979 |
| 8000 | 731.1 | 1089.5 | 6265.63 | 0.7861 |
| 20000 | 1885.1 | 2787.5 | 16695.31 | 4.0880 |
Conclusions
The principal benefit of XSLT for a JavaScript widget is flexibility at instantiation time. Since most Ajax developers already work with a server-side stack, being able to skip the client-side decoration step boosts performance — though at a bandwidth cost. Projects often involve a mix of large dynamic datagrids (best served from the server) and smaller hand-coded tables. The XSLT-based design lets developers choose either client or server transformation while preserving a consistent look and feel.
Required libraries (historical)
- prototype.js (Sam Stephenson)
- scriptaculous.js (Thomas Fuchs)
- sarissa.js (Manos Batsis)
- XSLDataGrid.css, XSLDataGrid.js, XSLDataGrid.xsl, Utility.js (Lindsey Simon)
Originally © 1998–2008 O'Reilly Media, Inc.