Firefox: HTML DOM fails if a local XSL transformation does not specify xsl:output

This nasty beast took me a while to figure out: if you do local XSL transforms in Firefox 1.5 and don't have the xsl:output directive in your main XSL stylesheet, HTML-specific DOM calls might not work.

The results are weird: for example, whatever is produced with the XSL transformation behaves like a HTML DOM object, but if you create a new element, it lacks HTML-specific DOM calls.

And the obvious solution: make sure you're always including ...
<xsl:output method="html" encoding="utf-8"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
... in your XSL stylesheet.

IE7 bug: addEventListener does not work with table row mouseover event

If you want to implement your JavaScript code using DOM-compliant events, you'd be unpleasantly surprised to learn that table rows in Internet Explorer do not respond to mouseover events attached to them with addEventListener. Firefox and Opera work as expected. The only way to achieve cross-browser compatibility is to use the old onmouseover properties: tablerow.onmouseover = myfunc; instead of tablerow.addEventListener("mouseover",myfunc).

Firefox 1.5 bug: table.rows property is empty when using XSL

If you generate a table in Firefox 1.5 with an XSL stylesheet within the browser from an XML document loaded from the server, the table's rows property will contain no rows. You can still get the rows using the childNodes property though.

To make matters worse, Firefox does not generate an implicit TBODY element in the DOM tree, but IE7 and Opera do. Makes for a nice nightmare if you aim at cross-browser support ... the workaround code is included below:
function recurseChildNodes(parent,tag,callback) {
if (! parent.nodeName) return;
if (parent.nodeName.toLowerCase() == tag) { callback(parent); return; }
if (! parent.childNodes) return;

for (var i = 0; i < parent.childNodes.length; i++) {
recurseChildNodes(parent.childNodes[i],tag,callback);
}
}


recurseChildNodes(table,"tr",callbackFunction);