Using JavaScript to Work with The Document Object Model — Part I

Most Web programmers are familiar with Dynamic HTML (DHTML) and the underlying Document Object Models developed by Netscape and Microsoft for their respective browsers. However, there is a unifying Document Object Model (DOM) developed by the W3C that is less well known and, hence, used less often. The W3C DOM has several advantages over the DHTML DOM — using its node structure it is possible to easily navigate and change documents despite the user agent used to display them. This article covers the basics of the W3C DOM and teaches you how to use JavaScript to transverse the nodes within it.

The W3C DOM is much more complex than shown within this article. There are several additional methods and properties at your disposal to use in manipulating documents. Further reading and information on the standard can be found on the W3C Web site at http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/Overview.html. Chapter 22 "JavaScript Objects and Dynamic HTML" of the book Web Standards Programmer's Reference: HTML, CSS, JavaScript, Perl, Python, and PHP also covers the details of the DHTML DOM.

The History of the DOM

Before diving into working with the DOM, a little history is necessary to put the technology in perspective. The Document Object Model was developed by the World Wide Web Consortium (W3C) to allow programming languages access to the underlying structure of a Web document. Using the DOM a program can access any element in the document, determining and changing attributes and even removing, adding, or rearranging elements at will.

It's important to note that the DOM is a type of application program interface (API) allowing any programming language access to the structure of a Web document. The main advantage of using the DOM is the ability to manipulate a document without another trip to the document's server. As such, the DOM is typically accessed and used by client-side technologies, such as JavaScript. Therefore, the coverage of the DOM in the book Web Standards Programmer's Reference: HTML, CSS, JavaScript, Perl, Python, and PHP appears in the JavaScript part of the book and is very JavaScript-centric.

The first DOM specification (Level 0) was developed at the same time as JavaScript and early browsers. It is supported by Netscape 2 onward.

There were two intermediate DOMs supported by Netscape 4 onward and Microsoft Internet Explorer (IE) versions 4 and 5 onward. These DOMs were proprietary to the two sides of the browser coin — Netscape and Microsoft IE. The former used a collection of elements referenced through a document.layers object, while the latter used a document.all object. To be truly cross-browser compatible, a script should endeavor to cover both of these DOMs instead of one or the other.

The latest DOM specification (Level 1) is supported by Mozilla and Microsoft Internet Explorer version 5 onward. Both browser developers participated in the creation of this level of the DOM and as such support it. However, Microsoft chose to continue to support its document.all model as well, while Netscape discontinued its document.layers model.

Keep in mind also that the DOM was originally intended to allow programs to navigate and change XML, not HTML, documents, so it contains many features a Web developer dealing only with HTML may never need.

Understanding the Document Object Model

The basis of the DOM is to recognize each element of the document as a node connected to other nodes in the document and to the document root itself. The best way to understand the structure is to look at an example. The following code shows an example document that renders as shown in Figure 1 and whose resulting DOM is shown in the illustration of Figure 2.

<html>
<head>
<title>Sample DOM Document</title>

<style type="text/css">

  div.div1 { background-color: #999999; }
  div.div2 { background-color: #BBBBBB; }
  table, table * { border: thin solid black; }
  table { border-collapse: collapse; }
  td { padding: 5px; }

</style>

<script type="text/JavaScript">

</script>

</head>

<body>
<div class="div1">
  <h1>Heading 1</h1>
  <table>
    <tr><td>Cell 1</td><td>Cell 2</td></tr>

    <tr><td>Cell 3</td><td>Cell 4</td></tr>
  </table>
  <p>Lorem ipsum dolor sit amet, consectetuer adipiscing
  elit, sed diam <b>nonummy nibh euismod</b> tincidunt ut laoreet
  dolore magna aliquam erat volutpat. Ut wisi enim ad minim
  veniam, quis nostrud exerci tation ullamcorper suscipit
  lobortis nisl ut aliquip ex ea commodo consequat.</p>

</div>
<div class="div2">
  <h1>Heading 2</h1>
  <p>Lorem ipsum dolor sit amet, consectetuer adipiscing
  elit, sed diam nonummy nibh euismod tincidunt ut laoreet
  dolore magna aliquam erat volutpat. Ut wisi enim ad minim
  veniam, quis nostrud exerci tation ullamcorper suscipit
  lobortis nisl ut aliquip ex ea commodo consequat.</p>
  <ol id="sortme">An ordered list
    <li>Gamma</li>

    <li>Alpha</li>
    <li>Beta</li>
  </ol>
</div>
</body>

</html>
Figure 1
Figure 1

Figure 2
Figure 2

As you can see, each node is joined to its neighbors using a familiar parent, child, sibling relationship. For example, the first DIV node is a child of the BODY node, and the DIV node in turn has three children — an H1 node, a P node, and an OL node. Those three children (H1, P, and OL) have a sibling relationship to one another.

Plain text, usually the content of nodes such as paragraphs (P), is referenced as textual nodes and is broken down as necessary to incorporate additional nodes. This can be seen in the first P node, which contains a bold (B) element. The children of the P node include the first bit of text up to the bold element, the bold element, and the text after the bold element. The bold element (B) in turn contains a text child, which contains the bolded text.

The relationships between nodes can be explored and traversed using the DOM JavaScript bindings, as described in the next section.

Using JavaScript to Work with The Document Object Model — Part I

DOM Node Properties and Methods

The DOM includes several JavaScript bindings that can be used to navigate a document's DOM. A subset of those bindings, used in JavaScript as properties and methods, is listed in the following two tables. The first table describes JavaScript's properties.

A full list of DOM JavaScript bindings can be found on the W3C's Document Object Model Level 1 pages, at http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ecma-script-language-binding.html.

PropertyDescription
attributesThis read-only property returns a named node mapNamedNodeMap containing the specified node's attributes.
childNodesThis read-only property returns a node list containing all the children of the specified node.
firstChildThis read-only property returns the first child node of the specified node.
lastChildThis read-only property returns the last child node of the specified node.
nextSiblingThis read-only property returns the next sibling of the specified node.
nodeNameThis read-only property returns a string containing the name of the node, which is typically the name of the element (P, DIV, TABLE, and so on).
nodeTypeThis read-only property returns a number corresponding to the node type (1 = element, 2 = text).
nodeValueThis property returns a string containing the contents of the node and is only valid for text nodes.
ownerDocumentThis read-only property returns the root document node object of the specified node.
parentNodeThis read-only property returns the parent node of the specified node.
previousSiblingThis read-only property returns the previous sibling of the specified node. If there is no node, the property returns null.

The second table describes JavaScript's methods.

MethodDescription
appendChild(newChild)Given a node, this method inserts the newChild node at the end of the children and returns a node.
cloneNode(deep)This method clones the node object. The parameter deep — (a Boolean) — specifies whether the clone should include the source object's attributes and children. The return value is the cloned node(s).
hasChildNodes()This method returns true if the node object has children nodes, false if the node object has no children nodes.
insertBefore(newChild, refChild)Given two nodes, this method inserts the newChild node before the specified refChild node and returns a node object.
removeChild(oldChild)Given a node, this method removes the oldChild node from the DOM and returns a node object containing the node removed.
replaceChild(newChild, oldChild)Given two nodes, this method replaces the oldChild node with the newChild node and returns a node object. Note that if the newChild is already in the DOM, it is removed from its current location to replace the oldChild.

Using JavaScript to Work with The Document Object Model — Part I

Traversing a Document's Nodes

Using the JavaScript bindings, it is fairly trivial to navigate through a document's nodes, as demonstrated in the following example.

Example: Navigating and Reporting a Document's Object Model

This example navigates through a document's nodes and returns the document's DOM.

Source

This example uses the document example from earlier in this article with scripting necessary to navigate the DOM:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>DOM Walk and Display</title>

<style type="text/css">

  div.div1 { background-color: #999999; }
  div.div2 { background-color: #BBBBBB; }

  table, table * { border: thin solid black; }
  table { border-collapse: collapse; }
  td { padding: 5px; }

</style>

<script type="text/JavaScript">
var s = new String();

// Add node's children to the listing (String s)
function showChildren(node,lvl) {

  // Only track elements (1), text (3), and the document (9)
  if ( node.nodeType == 1 || node.nodeType == 3 ||
       node.nodeType == 9 ) {
    // Add dashes to represent node level
    for (var x = 0; x < lvl; x++) { s = s + "--"; }
    // Report first 20 chars for text nodes
    if ( node.nodeType == 3 ) {
      mynodeType = node.nodeValue;
      if (mynodeType.length > 20) {
        mynodeType = mynodeType.slice(0,16) + "...";
      }
    } else {
      // Report "Element/Tag" for elements
      mynodeType = "Element/Tag";
    }
    s = s + "+ " + node.nodeName + " (" + mynodeType + ")\n";

    // If the node has children, let's report those too
    if ( node.hasChildNodes() ) {
      var children = node.childNodes;
      for (var i = 0; i < children.length; i++) {
        showChildren(children[i],lvl+1);
      }

    }

  }

}

function domwalk() {
  // Navigate through the DOM and report it in another window
  alert("Click OK to display the document's DOM");
  showChildren(document,0);
  displaywin = window.open("","displaywin",
      "width=400,height=400,scrollbars=yes,resizable=yes");
  displaywin.document.write("<pre>"+s+"</pre>");
}


</script>
</head>
<body onload="domwalk()">
<div class="div1">
  <h1>Heading 1</h1>
  <table>
    <tr><td>Cell 1</td><td>Cell 2</td></tr>

    <tr><td>Cell 3</td><td>Cell 4</td></tr>
  </table>
  <p>Lorem ipsum dolor sit amet, consectetuer adipiscing
  elit, sed diam <b>nonummy nibh euismod</b> tincidunt ut laoreet
  dolore magna aliquam erat volutpat. Ut wisi enim ad minim
  veniam, quis nostrud exerci tation ullamcorper suscipit
  lobortis nisl ut aliquip ex ea commodo consequat.</p>

</div>
<div class="div2">
  <h1>Heading 2</h1>
  <p>Lorem ipsum dolor sit amet, consectetuer adipiscing
  elit, sed diam nonummy nibh euismod tincidunt ut laoreet
  dolore magna aliquam erat volutpat. Ut wisi enim ad minim
  veniam, quis nostrud exerci tation ullamcorper suscipit
  lobortis nisl ut aliquip ex ea commodo consequat.</p>
  <ol id="sortme">An ordered list
    <li>Gamma</li>

    <li>Alpha</li>
    <li>Beta</li>
  </ol>
</div>
</body>

</html>

This code works by recursively calling the showChildren() function for each node that has children in the document (identified by the hasChildNodes() property). The nodes are added to a global string (s) until the end of the document is reached (there are no more nodes or children). The script then spawns a new window to display the full DOM as recorded in the string. (Note that your user agent must allow pop-up windows for this code to work.)

Output

The script displays the windows shown in Figure 3. The DOM is displayed with representative levels (dashes and pluses) in the new window.

Figure 3
Figure 3

Next Time

This article introduced the W3C Document Object Model and the JavaScript properties and methods you can use to traverse it. You can also use the values and types properties of nodes to effectively search the DOM for nodes, as well as modify node contents, properties and even order in the document. The next article in this series will demonstrate how to find a particular node.

This article is adapted from Web Standards Programmer's Reference: HTML, CSS, JavaScript, Perl, Python, and PHP by Steven M. Schafer (Wrox, 2005, ISBN: 0-7645-8820-6), from Chapter 21 "The Document Object Model." This is the first of a three-part series of articles on this topic. Steve programs in several languages and technologies, with extensive experience in Linux and related open-source platforms.

Copyright © 2000-2006 by WROX, a division of John Wiley & Sons, Inc.



About the Author

Steven M. Schafer

Steven Schafer programs in several languages and technologies, with extensive experience in Linux and related open-source platforms. He is the author of Web Standards Programmer's Reference: HTML, CSS, JavaScript, Perl, Python, and PHP (Wrox, 2005, ISBN: 0-7645-8820-6) as well as several other books and articles.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds