Using the DOM in Your Web Applications
Posted by Maciek Wed, 20 Sep 2006 17:13:26 GMT
The DOM (Document Object Model) can be a clear and useful way to represent and interact with XML documents. It can also be a rather obtuse and un-obvious way to work with data when you first come in contact with it. In spite of some of its more difficult parts (especially as one digs into DOM Level 2 and 3) , the core DOM API is fairly consistent. It is this consistency that offers programmers some of DOM’s great strengths: operational sameness from language-to-language and system-to-system, schema-to-schema—and, to a lesser extent, browser to browser. As one works with it, however, one comes to realize that DOM is only a piece of a puzzle that fits into a greater whole in the XML world, and this consistency is only part of that larger philosophy that embodies XML.
Where is the DOM Used, and Why?
With XML
I have sometimes found it hard to explain to people why the DOM is useful. This difficulty stems from the fact that it is also hard to convince people to start using XML, especially within the popular MySQL+PHP template-centric web application pattern. The advantages of using XML as a ligua franca in your web application is beyond the scope of this document. There are many books and web resources which cover the subject much better than I can, but I will touch on some of those issues throughout this document. This document will be useful if you involve XML at the various levels of your application and serialize your data as standardized XML documents throughout the logic, presentation and client-side layers. If you plan on using AJAX methodologies, this is very useful for keeping Unicode data “in check”.
Without XML
For those of you that are not using the above pattern, the DOM is still useful on the client side (i.e: in web browsers). Because it is a fairly consistent API at every layer, most of this document still applies to client-side usage of DOM APIs, where it can be used to manipulate the document the user is interacting with.
Layers and Role

The figure above depicts what might be the layers of a somewhat-typical web application framework. Information sits inside a database (the model) which is desired by the client (a human or a computer). Layers sit in between and transform and prepare the information for presentation or manipulation, as well as control access to the information. I began to understand why DOM was useful to me when I experienced problems while dealing with XML documents travelling up and down this stack of layers. There are a number of ways you can experience trouble as an XML document travels from layer to layer. Setting aside the larger issues of design and organization, I would guess (and have experienced) that the most frequent issue faced by users new to XML is keeping documents well-formed and parseable at all times. In his book Effective XML – a book which I highly recommend to programmers making extensive use of XML – XML guru Elliotte Harold, while mentioning that XML documents are “nothing more than unicode in angle brackets”, dedicates a sizeable chunk of his book discussing issues of well-formedness.
Keeping Things Clean and Reducing Headaches
One way to significantly reduce headaches in the creation and manipulation of XML data is by using a proper DOM API. Programmers should always favour using DOM over string concatenation to produce XML, otherwise they risk creating XML that is not really XML 1.0—not well-formed XML, in other words. Never manipulate XML with your own string-processing code. Unless your code can adhere strictly to the XML 1.0 standard, it won’t hold up in the real world!
Diving in With an Example
<HTML><HEAD></HEAD><BODY><P>The <STRONG>quick</STRONG> brown fox jumps over the <EM>lazy</EM> dog.</P><P>It was the best of times, it was the worst of times.</P></BODY></HTML>
Consider the following simple XML document above. From a DOM API’s perspective, this document contains the following:
- A root node with a nodeType of 1 and a nodeName of “HTML”.
- Two other nodes of the same type (1) with nodeNames, respectively, of “HEAD” and “BODY”, which are child nodes of the above “HTML” node. “BODY” has child nodes of its own, those in turn have more children, and so on.
- 6 text nodes, each with a nodeValue, of, respectively, “The ”, “quick”, ” brown fox jumps over the ”, “lazy”, ” dog.”, and “It was the best of times, it was the worst of times.”
It can be said that the nodes in the XML document are represented as a tree-based data structure and that there is one root node in this structure. Note the lack of extraneous whitespace or indenting in our example document. If this document were formatted with indenting and newlines and so forth, it would have many more text nodes, most of them consisting of newline and tab or space characters.
With respect to programmatically accessing a document of this kind, there are many methods you can consider. Load into a string, tokenize the angle brackets, use regular expressions, search and replace and so on. All of these methods will fail at one point or another unless the programmer puts an immense amount of work into the task, reads the entire XML 1.0 specification and writes a lot of code, at which point he will have written his own XML parser, and at which point using DOM has probably become a lesser concern. No matter. Re-inventing the wheel is clearly not a concern to the rest of us “get it done” programmers, who just want access to our data, and fast.
- Note: For the purposes of our example document remaining simple, we leave out the extra customary whitespace between tags, but in the real world you will encounter whitespace nodes in your documents. It is important to always write your code with the assumption that they might appear, no matter how hard you labour to force others to adhere to your schema/DTD or formatting style. Extra whitespace between nodes is not always semantically significant, anyhow.

The above figure shows two views of our example document. The primary view shows a file-folder-like tree with each node name in its proper place. The bottom view shows the document as rendered by the Mozilla browser. To the left of the primary view, we can see the result of inspecting the bottom-most text node in our document, the one containing the text “It was the best of times, it was the worst of times.”. The root node of our XML document, an “HTML” element, is close to the top of the tree view. In addition to our observations of the original text document, however, we can see that the DOM API in Mozilla has placed that root node as the child of another node known as #document. This root #document node corresponds not with any particular node within the document but with the XML document as a whole. Most DOM interactions begin with this top level node whether you are creating a new document or manipulating an existing one.
Using the DOM in Javascript-enabled Web Browsers
- Note: It is worth mentioning that most web browsers have some degree of support for DOM. It is fair to say that all modern browsers have support for DOM. DOM feature sets are, in order of increasing sophistication, ordered primarily by “levels” along with specific feature sets within these levels. At time of writing, the best support for DOM is found in Gecko-based browsers like Mozilla and Firefox. Mozilla’s DOM support is closely followed by KHTML-based browsers like Safari and Konqueror, with vastly improved support on the way. Gecko and KHTML-based browsers generally have full DOM1 and DOM2 support and partial (but rapidly improving) DOM3 support. The Opera browser comes next, with full support for DOM1 and partial (but useful) support for DOM2. Microsoft Internet Explorer has the poorest support of DOM (and will likely remain so), but supports enough of the DOM1 core specification to be useful, which is just fine for our purposes. Older versions of IE browsers have varying levels of DOM support. The worst offender is IE 5.2 for OS X, which has fatal some DOM bugs. Fortunately, users of that platform can always use Safari which happens to always co-exist with IE 5.2.
As developers of web applications, this leaves us with more or less excellent support for DOM1 everywhere, with a serious word of caution to users of IE 5.2 to switch to Safari.
Browser Examples
We can finally proceed with a real-world example of how to interact with an XML document in Javascript by using the DOM. Let’s amend our example from above with some scripting. To try out any of the following examples, simply paste into your favourite text editor, save as a .html file and load up in your the web browser of your choice (make sure it is reasonably new and has javascript enabled, of course).
<html>
<head>
<script type="text/javascript">
function testfunc() {
var paragraphs = document.getElementsByTagName('p');
for(var i in paragraphs){
var para=paragraphs[i];
for(var j in para.childNodes){
var child=para.childNodes[j];
if(child.nodeType==3){
// nodeType of 3 means this is a textnode
child.nodeValue=" spam! ";
}
}
}
}
</script>
</head>
<body onload='testfunc();'>
<p>The <strong>quick</strong> brown fox jumps over the
<em>lazy</em> dog.</p><p>It was the best of times,
it was the worst of times.</p>
</body>
</html>

Above, the javascript function testfunc() makes use of the DOM. From the top:
- We ask the document (a variable refering to an HTMLDocument object instance available pretty much everywhere within a browser’s javascript scope) for a nodelist (a fancy DOM name for an array of DOM nodes) containing all the elements in the document with the tagName (also known as nodeName) of “p”. We do this by calling its getElementsByTagName function.
- We iterate through list of paragraph nodes.
- For each paragraph node, we iterate through each of its children.
- For each child node, if it is a text node (nodeType==3), set its nodeValue (ie. its text) to the string ” spam! “
The program executes at the instant that the browser is done rendering, so it is unlikely that you will see the original document when you load the example into a web browser. Once the program is finished, it will have changed the text value of every text node that is a child of a paragraph element to read ” spam! ”. This program illustrates a potentially complicated document transformation with a simple loop, without any need to write any parsing code or regular expressions, or write a bunch of display functions to regenerate the document from javascript arrays. DOM does all the work for you, allowing you to focus on the transformation itself.
Example 2
Let’s try something slightly more interesting:
<html>
<head>
<script type="text/javascript">
function testfunc(node){
for(var i in node.childNodes){
var somenode=node.childNodes[i];
if(somenode.nodeType==3
&& somenode.parentNode.nodeName.toLowerCase()!="em"
&& somenode.parentNode.nodeName.toLowerCase()!="strong" ){
somenode.nodeValue=" *"+somenode.nodeValue.toUpperCase()+"* ";
} else if (somenode.nodeType==1) {
if(somenode.nodeName.toLowerCase()=="em"){
somenode.setAttribute("style","border:2px solid blue;");
} else if (somenode.nodeName.toLowerCase()=="strong"){
somenode.setAttribute("style","border:2px solid red;");
}
testfunc(somenode);
}
}
}
</script>
</head>
<body onload='testfunc(document.body);'>
<p>The <strong>quick</strong> brown fox jumps over the
<em>lazy</em> dog.</p><p>It was the best of times,
it was the worst of times.</p>
</body>
</html>

In the above code, we have changed testfunc into a recursive function that iterates through the subtree rooted at the node passed in as the parameter node. Initially we pass it the node document.body (which is a shortcut in the HTML DOM to access the body node of the document). This causes the function to visit any descendant nodes of the document’s body element. You can see the result of this operation in the above figure. At each step in the recursion, the function does a few things:
- Iterates through any child nodes visible from the current node.
- Surrounds in *’s and uppercases any text node that is not a child of an em or strong element.
- Adds a bit of flair to em elements by giving them a blue border, and does the same thing for strong elements, but in the color red.
- Visits any child further child nodes (which causes the function to travel deeper into the tree until it runs out of nodes to visit).
This program performs a more sophisticated manipulation of the document. By now you can probably imagine some interesting possibilities with just a few very basic “core” functions.
Using the DOM in PHP 5
With the release of PHP 5, PHP users finally have a real DOM API provided by libxml (previous versions of the language and its DOM API were woefully inadequate). The new DOM, along with PHP 5's true OO, a mountain of plug n' play libraries, add-ons, documentation, server vendors, applications, communities, etc will hopefully expose more people to DOM and other XML technologies than ever before.
PHP 5’s DOM support is much better than the DOM support developers can expect to find in the average browser. Unlike in most browser implementations, you can load, save, and create new documents, which is extremely useful. You can also copy parts of one document to another. Here’s an example of DOM manipulation in PHP5:
<?
$doc = new DOMDocument();
$doc->loadXML("<html />");
$html_elements = $doc->getElementsByTagName("html");
// get <html /> element
$root = $html_elements->item(0);
// add a <head /> element and its children
$myhead = $doc->createElement("head");
$title = $doc->createElement("title");
$title->appendChild($doc->createTextNode("Quick Brown Fox"));
$myhead->appendChild($title);
$root->appendChild($myhead);
// add the <body /> element and its children
$mybody = $doc->createElement("body");
$mybody->setAttribute("style","background-color:#222;color:#aaa;");
$myspan = $doc->createElement("span");
$myspan->appendChild($doc->createTextNode("The "));
// create a <strong /> element
$mystrong = $doc->createElement("strong");
$mystrong->setAttribute("style","color:#f44;");
// give it a child text node with the text we want
$mystrong->appendChild($doc->createTextNode("quick "));
$myspan->appendChild($mystrong);
$myspan->appendChild($doc->createTextNode("brown fox jumps over the lazy dog."));
$mybody->appendChild($myspan);
// add body to the <html /> element
$root->appendChild($mybody);
// turn the DOM document object into a string containing the XML
print $doc->saveXML();
?>
Above, we bootstrap a document with an html element. We then create a bunch of children and construct a document tree. At the end, we call saveXML() to $doc, which serializes the DOM object into an XML document. The output of saveXML() is below:
<?xml version="1.0"?>
<html><head><title>Quick Brown Fox</title></head>
<body style="background-color:#222;color:#aaa;">
<span>The <strong style="color:#f44;">quick </strong>brown fox jumps over the lazy dog.</span>
</body></html>
Depending on your DOM implementation, you are often not limited to seeking out nodes with functions like getElementsByTagName() and getElementById(). You can seek out nodes and manipulate documents in more sophisticated ways by combining DOM with an addressing language known as XPath. PHP 5 allows you to collect nodes from any location in your document into something known as a DOM Nodelist. This is simply a list of references to these nodes.
<?
// create a sample XML document string
ob_start();
?>
<continent name="North America">
<cities>
<city name="New York" country="USA" />
<city name="Montreal" country="CAN" />
<city name="Toronto" country="CAN" />
<city name="Chicago" country="USA" />
<city name="Seattle" country="USA" />
<city name="San Francisco" country="USA" />
<city name="Vancouver" country="CAN" />
</cities>
</continent>
<?
$xml_string = ob_get_clean();
// load up document string into a DOM object
$doc = new DOMDocument();
$doc->loadXML($xml_string);
// grab a Nodelist of city nodes with attribute country="USA"
$xpath = new DOMXPath($doc);
$USA_cities = $xpath->query("//city[@country='USA']");
// remove just the cities in the nodelist from the document
if($USA_cities->length > 0){
foreach($USA_cities as $city_to_remove){
$city_parent = $city_to_remove->parentNode;
$city_parent->removeChild($city_to_remove);
}
}
// Print out the serialized XML document
print $doc->saveXML();
?>
Above, we perform a simple XPath query to fetch city nodes from the document that have the attribute country whose value is “USA”. Using only DOM, this would have required a loop at best. At worst, depending on the complexity of the document and the placement of nodes throughout, a recursive function might have to be written to search through the entire document and seek out those nodes. Instead of writing custom functions like this every time you need to find nodes in a document, just use XPath. XPath makes very complicated queries on node sets very simple. DOM then takes over and provides the ability to manipulate those nodes somehow. The two work together beautifully. Below you can see the output of the above code.
<?xml version="1.0"?>
<continent name="North America">
<cities>
<city name="Montreal" country="CAN"/>
<city name="Toronto" country="CAN"/>
<city name="Vancouver" country="CAN"/>
</cities>
</continent>
As you can see, the text nodes that contain the indenting whitespace are carefully preserved in this operation. Most DOM APIs give you the ability to explicitly control how whitespace text nodes are treated in a document. This integrity is important if whitespace is a significant part of your data.
In a Nutshell..
By now you can see that at its core, the DOM basically covers a few basic operations:
- Creating nodes (elements).
- Creating text nodes (“node type = 3”).
- Setting node attributes.
- Adding child nodes to other nodes.
- Finding nodes in a document and placing them in a list.
- Removing a child from a node.
This is, of course, just the tip of the iceberg. DOM contains a huge amount of functionality and features including validation, traversal and range, exceptions, etc, etc. The most complete and authoritative information about DOM can be found at the W3C’s DOM Technical Reports page. Developers that get into the habit of reading these specifications and relating them to the various languages and environments where they make use of the DOM (or other w3c technologies) will find that they have a much better understanding these things and how they are supposed to be used.








great article, also whole site is very good.