The W3C « XHTML media types » note mentions that:
XHTML documents served as ‘text/html’ will not be processed as XML [XML10], e.g. well-formedness errors may not be detected by user agents. Also be aware that HTML rules will be applied for DOM and style sheets (see C.11 and C13 of [XHTML1] respectively).
I have been bitten by this rule while developing the « Hello World » application that will illustrate the first chapter of our upcoming Web 2.0 book.
In this sample application, I am using Javascript to fill information in XHTML elements that act as place holders and noticed that updating elements could sometimes lead to erasing their following siblings:
[<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Repro case</title>
<script type="text/javascript">
function init() {
// here, we still have a p[@id='bar'] element
alert("bar: " + document.getElementById("bar"));
document.getElementById("foo").innerHTML="foo";
// but now, the p[@id='bar'] element has disappeared...
alert("bar: " + document.getElementById("bar"));
}
</script>
</head>
<body onload="init()">
<div id="foo"/>
<p id="bar"/>
</body>
</html>
One of the things that I found most surprising is that the three browsers I was testing (Firefox, Opera and Mozilla) showed the same « bug ».
It took me a while to understand that the behaviour is dictated by the media type associated to the document: when the media type is « text/html », the document is interpreted as HTML despite its XML declaration and the trailing slash in the div start tag is ignored. The document body seen by the browser is thus equivalent to:
<body onload="init()">
<div id="foo">
<p id="bar"></p>
</div>
</body>
The p element which is a following sibling of the div element in XML becomes a child of the div element in HTML mode!
In Firefox or Opera, the clean way to fix that would be to send the proper media type (application/xhtml+xml) but unfortunately Internet Explorer doesn’t support it.
A workaround is to avoid using empty tags in XHTML and a comment can be included if you want to make sure that no badly behaved editor will minimise your document:
<body onload="init()">
<div id="foo"><!-- --></div>
<p id="bar"><!-- --></p>
</body>
Note that this isn’t necessary for the p element but that it doesn’t do any harm and looks more consistent.