Writing JavaScript for XHTML

  • Revision slug: Writing_JavaScript_for_XHTML
  • Revision title: Writing JavaScript for XHTML
  • Revision id: 69727
  • Created:
  • Creator: Manuel Strehl
  • Is current revision? No
  • Comment New page: Website authors have started to write now for about 7 years XHTML files instead of HTML 4.01. But though, almost no XHTML file viewed over the web is served with the corresponding, correct...

Revision Content

Website authors have started to write now for about 7 years XHTML files instead of HTML 4.01. But though, almost no XHTML file viewed over the web is served with the corresponding, correct MIME type, that is, with application/xhtml+xml. This is for one reason due to a certain browser, that is not capable of XHTML as XML, but it also is the experience, that the JavaScript, authored for HTML, suddenly breaks in an XML environment.

This article shows some of the reasons alongside with strategies to remedy the problems. To test these features locally, use Firefox's extension switch.

Problem: The DOM changed

The central object in the DOM, the document object, is of type HTMLDocument in HTML, whereas it is an XMLDocument in XML files. This has an especially huge impact on methods JavaScript authors are used to in daily work. Take the document.getElementsByTagName method, for example. This is a DOM 1 method, which means, there are no XML namespaces respected. Take a look at this common snippet:

var headings = document.getElementsByTagName("h1");
for( var i = 0; i < headings.length; i++ ) {
  doSomethingWith( headings[i] );
}

Now comes the problem: in XHTML, served as XML, all elements are in the XHTML namespace (remember the xmlns attribute in the html tag?). This means, our plain old DOM 1 method suddenly finds no elements anymore. Bang! Immediately 80% of today's JavaScripts on the web crashed, including our snippet above.

Solution: Use DOM 2 methods

The W3C introduced the DOM 2, addressing the needs of distinguishing namespaces. Perhaps you have seen sometimes before a method like document.getElementsByTagNameNS? The difference is the NS part, meaning, it looks for namespaces. How do we use this method? This is straight forward:

var headings = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml","h1");
for( var i = 0; i < headings.length; i++ ) {
  doSomethingWith( headings[i] );
}

The only difference is the mentioning of the namespace the element is in. Okay, more letters to type, but you can define shorthands. Then, let's take only DOM 2 methods from now on!

But wait! Now, taking a look in our HTML file, the script breaks again! Remember, in HTML the elements are in no namespace at all! So, what we have to do now is writing a wrapper, that determines, if we are dealing with an HTML or an XML file. Check this piece of code out:

Node.prototype.getHTMLByTagName(tagName) {
  if( document.contentType == "text/html" ) {
    return this.getElementsByTagName(tagName);
  } else {
    return this.getElementsByTagNameNS("http://www.w3.org/1999/xhtml",tagName);
  }
}

What does this code do? It extends all nodes with a method getHTMLByTagName, that distinguishes between the content type of the document element. For IE, you would have to take a look at the document.mimeType property instead.

Revision Source

<p>Website authors have started to write now for about 7 years XHTML files instead of HTML 4.01. But though, almost no XHTML file viewed over the web is served with the corresponding, correct MIME type, that is, with <i>application/xhtml+xml</i>. This is for one reason due to a certain browser, that is not capable of XHTML as XML, but it also is the experience, that  the JavaScript, authored for HTML, suddenly breaks in an XML environment.
</p><p>This article shows some of the reasons alongside with strategies to remedy the problems. To test these features locally, use <a href="en/XML_in_Mozilla#XHTML">Firefox's extension switch</a>.
</p>
<h3 name="Problem:_The_DOM_changed"> Problem: The DOM changed </h3>
<p>The central object in the DOM, the <i>document</i> object, is of type <i>HTMLDocument</i> in HTML, whereas it is an <i>XMLDocument</i> in XML files. This has an especially huge impact on methods JavaScript authors are used to in daily work. Take the <i>document.getElementsByTagName</i> method, for example. This is a DOM 1 method, which means, there are no XML namespaces respected. Take a look at this common snippet:
</p>
<pre class="eval">var headings = document.getElementsByTagName("h1");
for( var i = 0; i &lt; headings.length; i++ ) {
  doSomethingWith( headings[i] );
}
</pre>
<p>Now comes the problem: in XHTML, served as XML, <b>all</b> elements are in the XHTML namespace (remember the <i>xmlns</i> attribute in the <i>html</i> tag?). This means, our plain old DOM 1 method suddenly finds no elements anymore. <b>Bang!</b> Immediately 80% of today's JavaScripts on the web crashed, including our snippet above.
</p>
<h3 name="Solution:_Use_DOM_2_methods"> Solution: Use DOM 2 methods </h3>
<p>The W3C introduced the DOM 2, addressing the needs of distinguishing namespaces. Perhaps you have seen sometimes before a method like <i>document.getElementsByTagNameNS</i>? The difference is the <b>NS</b> part, meaning, it looks for namespaces. How do we use this method? This is straight forward:
</p>
<pre class="eval">var headings = document.getElementsByTagNameNS(<b>"http://www.w3.org/1999/xhtml"</b>,"h1");
for( var i = 0; i &lt; headings.length; i++ ) {
  doSomethingWith( headings[i] );
}
</pre>
<p>The only difference is the mentioning of the namespace the element is in. Okay, more letters to type, but you can define shorthands. Then, let's take only DOM 2 methods from now on!
</p><p>But wait! Now, taking a look in our HTML file, the script breaks again! Remember, in HTML the elements are in <b>no namespace at all</b>! So, what we have to do now is writing a wrapper, that determines, if we are dealing with an HTML or an XML file. Check this piece of code out:
</p>
<pre class="eval">Node.prototype.getHTMLByTagName(tagName) {
  if( document.contentType == "text/html" ) {
    return this.getElementsByTagName(tagName);
  } else {
    return this.getElementsByTagNameNS("http://www.w3.org/1999/xhtml",tagName);
  }
}
</pre>
<p>What does this code do? It extends all nodes with a method <i>getHTMLByTagName</i>, that distinguishes between the content type of the document element. For IE, you would have to take a look at the document.mimeType property instead.
</p>
Revert to this revision