Chapter 17. The Document Object
Model
document object model (DOM) is an application programm g interface (API) for
a document (such as an HTML docum m g
s elements (such as HTML tags f text) at make up
ocument. JavaScript-enabled web browsers have always defi ed a document object
a web-browse ay specify, ple, that the forms in an HTML
ocument are accessible through the forms[] array of the Document object.
In this chapter, we'll discuss the W3C DOM, a standard document object model defined
by the World Wide Web Consortium and implemented (at least partially) by Netscape 6
and Internet Explorer 5 and 6. This DOM standard
[1]
A in
representing
he variou
ent) and accessing and
nd strings o
anipulatin
att
d
a th
n
th
model; r DOM m for exam
d
is a full-featured superset of the
traditional web-browser DOM. It represents HTML (and XML) documents in a tree
structure and defines properties and methods for traversing the tree and examining and
modifying its nodes. Other portions of the standard specify techniques for defining event
handlers for the nodes of a document, working with the style sheets of a document, and
manipulating contiguous ranges of a document.
[1]
Technically, the W3C issues "recommendations." These recommendations serve the same purpose and carry the same weight as international
standards do, however, and are called "standards" in this book.
This chapter begins with an overview of the DOM standard and then describes the core
portions of the standard for working with HTML documents. The discussion of the core
standard is followed by short sections that explain the DOM-like features of Internet
s of
nced
HTML documents have a hierarchical structure that is represented in the DOM as a tree
structure. The nodes of the tree represent the various types of content in a document. The
tree representation of an HTML document primarily contains nodes representing
elements or tags such as
<body> and <p> and nodes representing strings of text. An
HTML document may also contain nodes representing HTML comments.
[2]
Explorer 4 and Netscape 4. The chapter ends with an overview of two optional part
the DOM standard that are closely related to the core. Later chapters cover adva
DOM features for working with style sheets and events.
17.1 An Overview of the DOM
The DOM API is not particularly complicated, but before we can begin our discussion of
programming with the DOM, there are a number of things you should understand about
the DOM architecture.
17.1.1 Representing Documents as Trees
Consider the
following simple HTML document:
[2]
The DOM can also be used to represent XML documents, which have a more complex syntax than HTML documents, and the tree
representation of such a document may contain nodes that represent XML entity references, processing instructions, CDATA sections, and so
on. Most client-side JavaScript programmers do not need to use the DOM with XML documents, and although the XML-specific features of
the DOM are covered in the DOM reference section, they are not emphasized in this chapter.
<html>
<head>
<title>Sample Document</title>
<h1>An HTML Document</h1>
<p>This is a <i>simple</i> document.
</body>
</html>
The DOM representation of this document is the tree pictured in Figure 17-1
</head>
<body>
.
Figure 17-1. The tree representation of an HTML document
If you are not already familiar with tree structures in computer programming, it is helpfu
to know that they borrow terminology from family trees. The node directly above a node
is the
l
e
17.1.2 Nodes
parent of that node. The nodes one level directly below another node are the
children of that node. Nodes at the same level, and with the same parent, are siblings. Th
set of nodes any number of levels below another node are the descendants of that node.
And the parent, grandparent, and all other nodes above a node are the ancestors of that
node.
The DOM tree structure illustrated in
Figure 17-1 is represented as a tree of various type
of Node objects. The Node interface
s
[3]
defines properties and methods for traversing and
manipulating the tree. The
childNodes property of a Node object returns a list of
children of the node, and the firstChild , lastChild, nextSibling,
previousSibling, and parentNode properties provide a way to traverse the tree o
nodes. Methods such as
f
The DOM standard defines interfaces, not classes. If you are not familiar with the term interface in object-oriented programming, you can
think of it as an abstract kind of class. We'll describe the difference in more detail later in this DOM overview.
17.1.2.1 Types of nodes
Different types of nodes in the document tree are represented by specific subinterfaces of
Node. Every Node object has a nodeType property that specifies what kind of node it is.
If the nodeType property of a node equals the constant Node.ELEMENT_NODE, for
example, you know the Node object is also an Element object and you can use all the
methods and properties defined by the Element interface with it. Table 17-1
appendChild( ) , removeChild( ), replaceChild( ), and
insertBefore( ) enable you to add and remove nodes from the document tree. We'll
see examples of the use of these properties and methods later in this chapter.
[3]
lists the node
types commonly encountered in HTML documents and the nodeType value for each one.
Table 17-1. Common node types
Interface nodeType constant nodeType value
Element
Node.ELEMENT_NODE
1
Text
Node.TEXT_NODE
3
Document
Node.DOCUMENT_NODE
9
Comment
Node.COMMENT_NODE
8
DocumentFragment
Node.DOCUMENT_FRAGMENT_NODE
11
Attr
Node.ATTRIBUTE_NODE
2
The Node at the root of the DOM tree is a Document object. The documentElement
property of this object refers to an Element object that represents the root element of the
document. For HTML documents, this is the <html> tag that is either explicit or implicit
in the docu t nodes,
in addition cts,
which represent tags such as <html> and <i>, and Text objects, which represent strings
of text. If the docum comments, those comments are repres
the DOM tree by Comment
ment. (The Document node may have other children, such as Commen
to the root element.) The bulk of a DOM tree consists of Element obje
ent parser preserves ented in
objects. Figure 17-2 shows a partial class hierarchy for these
er core DO nterfaand oth M i ces.
Figure 17-2. A partial class hierarchy of the core DOM API
f ement (such as the src and width attributes of an <im may
, setAttribute(
e( ) met .
Another, more awkward way to work with attributes is with the getAttributeNode( )
ich re an A ute and its value. (One reason
to use this more awkward technique is that the Attr interface defines a specified
property that allows you to determine whether the attribute is literally specified in the
document, or whether its value is a default value.) The Attr interface appears in Figure
17.1.2.2 Attributes
The attributes o
be queried, set, and deleted using the
an el g> tag)
, and getAttribute( )
hods of the Element interface
)
removeAttribut
method, wh turns ttr object representing an attrib
17-2, and it is a type of node. Note, however, that Attr objects do not appear in the
childNodes[] array of an element and are not directly part of the document tree in the
way that Element and Text nodes are. The DOM specification allows Attr nodes to be
accessed through the attributes[] array of the Node interface, but Microsoft's Internet
Explorer defines a different and incompatible
attributes[] array that makes it
impossible to use this feature portably.
17.1.3 The DOM HTML API
The DOM standard was designed for use with both XML and HTML documents. The
core DOM API -- the Node, Element, Document, and other interfaces -- are relatively
generic and apply to both types of documents. The DOM standard also includes
interfaces that are specific to HTML documents. As you can see from Figure 17-2,
HTMLDocument is an HTML-specific subinterface of Document, and HTMLElement is
an HTML-specific subinterface of Element. Furthermore, the DOM defines tag-specific
interfaces for many HTML elements. These tag-specific interfaces, such as
HTMLBodyElement and HTMLTitleElement, typically define a set of properties that
mirror the HTML tag's attributes.
The HTMLDocument interface defines various document properties and methods that
were supported by browsers prior to W3C standardization. These include the location
property, forms[] array, and write( ) method, which are described in Chapter 13,
Chapter 14, and Chapter 15.
The HTMLElement interface defines id, style, title, lang, dir , and className
properties. These properties allow convenient access to the values of the id, style,
title, lang, dir, and class attributes, which are allowed on all HTML tags. A number
of HTML tags, listed in Table 17-2, accept no attributes other than these six, and so are
fully represented by the HTMLElement interface.
Table 17-2. Simple HTML tags
<abbr> <acronym> <address> <b> <bdo>
<big> <center> <cite> <code> <dd>
<dfn> <dt> <em> <i> <kbd>
<noframes> <noscript> <s> <samp> <small>
<span> <strike> <strong> <sub> <sup>
<tt> <u> <var>
All other HTML tags have corresponding interfaces defined by the HTML portion of the
DOM specification. For many HTML tags, these interfaces do nothing more than provide
re
erred) way to query and set attribute values is with the getAttribute( )
and setAttribute( ) methods of the Element object.
a set of properties that mirror their HTML attributes. For example, the
<ul> tag has a
corresponding HTMLUListElement interface, and the <body> tag has a corresponding
HTMLBodyElement interface. Because these interfaces simply define properties that a
standardized by the HTML standard, they are not documented in detail in this book. You
can safely assume that the HTMLElement object that represents a particular HTML tag
has properties for each of the standard attributes for that tag (but see the naming
conventions described in the next section). Note that the DOM standard defines
properties for HTML attributes as a "convenience" to script writers. The general (and
possibly pref
Some of the interfaces defined in the HTML DOM define additional properties or
methods, other than those that mirror HTML attribute values. For example, the
HTMLInputElement interface defines focus( ) and blur( ) methods, and the
HTMLFormElement interface defines and methods and a
ave been made part of the DOM standard for backward compatibility with existing
practice. Interfaces like these are documented in the DOM reference section. You can
usually also find information about the "existing practice" portions of these interfaces in
the client-side reference section, although this information is typically referenced under a
name that also predates DOM standardization; for example, you can find information
about HTMLFormElement and HTMLInputElement in the client-side reference section
When w
ple words, the first
re capitalized. Thus, the
maxlength attribute
nput> tag translates into the maxLength property of HTMLInputElement.
When an HTML attribute name conflicts with a JavaScript keyword, it is prefixed with
the string "html" to avoid the conflict. Thus, the for attribute of the <label> tag
translates to the htmlFor property of the HTMLLabelElement. An exception to this rule
is the class attribute (which can be specified for any HTML element); it translates to the
className property of HTMLElement.
[4]
submit( ) reset( ) length
property. Methods and properties like these typically predate DOM standardization and
h
under "Form" and "Input."
17.1.3.1 HTML naming conventions
orking with the HTML-specific portions of the DOM standard, you should be
L-specific interfaces aware of some simple naming conventions. Properties of the HTM
e property name consists of multibegin with lowercase letters. If th
letters of the second and subsequent words a
of the <i
[4]
The name className is misleading, because in addition to specifying a single class name, this property (and the HTML attribute it
represents) can also specify a space-separated list of class names.
17.1.4 DOM Levels and Features
There are two versions, or "levels," of the DOM standard. DOM Level 1 was
standardized in October, 1998. It defines the core DOM interfaces, such as Node,
Element, Attr, and Document, and also defines various HTML-specific interfaces. DOM
Level 2 was standardized in November, 2000.
[5]
In addition to some updates to the core
interfaces, this new version of the DOM is greatly expanded to define standard APIs for
working with document events and CSS style sheets and to provide additional tools for
er
Level 1 standard.
working with ranges of documents. As of this writing, the DOM Working Group at the
W3C is working to standardize DOM Level 3. You may also sometimes see a reference
to DOM Level 0. This term does not refer to any formal standard but is used to ref
informally to the common features of the HTML document object models implemented
by Netscape and Internet Explorer prior to W3C standardization.
[5]
Except for the HTML-specific portions of the standard, which are still at the "working draft" stage as of November 2001. Fortunately, the
current working draft is presumed stable and includes only minor changes (documented in this book) from the HTML-specific portions of the
As of Level 2, the DOM standard has been "modularized." The core module, which
nt, and
s are
o
implementation. The DOM implementation of a web browser would obviously support
defines the basic tree structure of a document with the Document, Node, Eleme
Text interfaces (among others), is the only required module. All other module
ptional and may or may not be supported, depending on the needs of the
the HTML module, since web documents are written in HTML. Browsers that support
CSS style sheets typically support the StyleSheets and CSS modules, because (as we'll
see in
Chapter 18) CSS styles play a crucial role in Dynamic HTML programming.
Similarly, since almost all interesting client-side JavaScript programming requires event-
o support the Events module of
the DOM specification. Unfortunately, the le was only recently defined by
ot yet widely supported at the time of this writing.
e'll see a complete list of DOM Level 2 modules in the next section.
s -- most
handling capabilities, you would expect web browsers t
Events modu
the DOM Level 2 specification and is n
W
17.1.5 DOM Conformance
At the time of this writing, no browser is completely conformant to the DOM standard.
Recent releases of Mozilla come closest, and complete DOM Level 2 conformance is a
goal of the Mozilla project. Netscape 6.1 does a good job of conforming to the most
important Level 2 modules, and Netscape 6.0 does an adequate job but has gaps in its
coverage. Internet Explorer 6 is mostly compliant (with at least one annoying exception)
with the Level 1 DOM, but does not support many of the Level 2 module
notably the Events module, which is the topic of Chapter 19. Internet Explorer 5 and 5.5
have substantial gaps in their conformance but support key DOM Level 1 methods well
enough to run most of the examples in this chapter. The Macintosh version of IE 5 has
considerably better support for the DOM than the Windows version of IE 5.
In addition to Mozilla, Netscape, and Internet Explorer, several other browsers offer at
least partial support for the DOM. The number of available browsers has become too
large, and the rate of change in the area of standards support has grown too fast, for this
book to even attempt to provide definitive statements about which browsers support
which particular DOM features. Therefore, you'll have to rely on other information
sources to determine exactly how conformant the DOM implementation in any particu
web browser is.
One source for conformance information is the implementation itself. In a con
implementation, the
implementation property of the Do
lar
formant
cument object refers to a
ing
es
DOMImplementation object that defines a method named hasFeature( ). You can use
this method (if it exists) to ask an implementation whether it supports a specific feature
(or module) of the DOM standard. For example, to determine whether the DOM
implementation in a web browser supports the basic DOM Level 1 interfaces for work
with HTML documents, you could use the following code:
if (document.implementation &&
document.implementation.hasFeature &&
document.implementation.hasFeature("html", "1.0")) {
// The browser claims to support Level 1 Core and HTML interfac
}
The hasFeature( ) method takes two arguments: the first is the name of the feature to
check, and the second is a version number, expressed as a string. It returns true if the
specified version of the specified feature is supported. Table 17-3 lists the feature
name/version number pairs that are defined by the DOM Level 1 and Level 2 standards.
Note that the feature names are case-insensitive: you can capitalize them any way you
support of a feature and are therefore implied by a return value of true. For example, if
indicates that the MouseEvents module is supported, this implies that
( )
choose. The fourth column of the table specifies what other features are required for
hasFeature( )
UIEvents is also supported, which in turn implies that the Events, Views, and Core
modules are supported.
Table 17-3. Features that can be tested with hasFeature
Feature name Version Description Implies
HTML 1.0 Level 1 Core and HTML interfaces
XML 1.0 Level 1 Core and XML interfaces
Core 2.0 Level 2 Core interfaces
HTML 2.0 Level 2 HTML interfaces Core
XML 2.0 Level 2 XML-specific interfaces Core
Views 2.0 AbstractView interface Core
StyleSheets 2.0 Generic style-sheet traversal Core
CSS 2.0 CSS styles Core, Views
CSS2 2.0 CSS2Properties interface CSS
Events 2.0 Event-handling infrastructure Core
UIEvents 2.0
User-interface events (plus Events and
Views)
Events,
Views
MouseEvents 2.0 Mouse events UIEvents
HTMLEvents 2.0 HTML events Events
MutationEvents 2.0 Document mutation events Events
Range 2.0 Document range interfaces Core
Traversal 2.0 Document traversal interfaces Core
In Internet Explorer 6 (on Windows), hasFeature( ) returns true only for the feature
HTML and Version 1.0. It does not report compliance to any of the other features listed
in Table 17-3 (although, as we'll see in Chapter 18, it supports the most common uses of
e names
This book documents the interfaces that make up all of the DOM modules listed in Table
the CSS2 module.) In Netscape 6.1, hasFeature( ) returns true for most featur
and version numbers, with the notable exceptions of the Traversal and MutationEvents
features. It returns for the Core and CSS2 features with Version 2.0, indicating false
good).incomplete support (even though support for these features is quite
17-3. The heCore, HTML, Traversal, and Range modules are covered in this chapter. T
StyleSheets, CSS, and CSS2 modules are covered in Chapter 18, and the various Event
modules (except MutationEvents) are covered in Chapter 19. The DOM reference
includes complete coverage of all modules.
section
6
ith
too voluminous and volatile to include in a printed book.
an active web developer, you undoubtedly already know or will discover many
t
e of this writing, the test suite effort is just
getting off e to be an invaluable resource for fine-grained
compliance testing of DOM implementations. See
/>The hasFeature( ) method is not always perfectly reliable. As previously noted, IE
reports Level 1 compliance to HTML features even though there are some problems w
its compliance. On the other hand, Netscape 6.1 reports noncompliance to the Level 2
ture even though it is mostly compliant. In both cases, you need more detailed Core fea
information about exactly what is and is not compliant. This is exactly the type of
ormation that is inf
If you are
browser-specific support details on your own. There are also resources on the Web that
can help you. Most importantly, the W3C (in collaboration with the U.S. National
Institute of Standards and Technology) is working on developing an open source tes
suite for DOM implementations. At the tim
the ground, but it ought to prov
for
details.
The Mozilla organization has a set of test suites for a variety of standards, including
DOM Level 1 (available at
Netscape
has published a test suite that includes some DOM Level 2 tests (available
at
). Netscape has also
published a partisan (and dated) comparison of DOM compliance of an early Mozilla
release versus IE 5.5 (available at
Finally, you can also find
compatibility and compliance information at independent sites on the Web. One notable
site is published by Peter-Paul Koch. You can find a link to his DOM Compatibility
Table from his main JavaScript page ( />17.1.5.1 DOM conformance in Internet Explorer
Because IE is the most widely used web browser, a few special notes about its
5 and later versions
support the Level 1 Core and HTML features well enough to run the examples in this
compliance to the DOM specifications are appropriate here. IE
chapter, and they support the key Level 2 CSS features well enough to run most of the
examples in Chapter 18. Unfortunately, IE 5, 5.5, and 6 do not support the DOM Level 2
Events module, even though Microsoft participated in the definition of this module and
had ample time to implement it for IE 6. As we'll see in Chapter 19, event handling
crucial for client-side event handling, and IE's lack of support for the standard event
is
model impedes the development of advanced client-side web applications.
gious problem, and the one you are most likely to encounter, is a minor but
de interface.
f
at
_NODE
do not exist.
nt
rogramming style to use constants instead of hardcoded integer literals in your
programs to define these constants if they are missing:
e = { // If there is no Node object, define one
llowing properties and
e are HTML node types
EXT_NODE: 3, // For XML-specific nodes, you need to add
COMMENT_NODE: 8, // other constants here.
DOCUMENT_NODE: 9,
}
17.1.6 Language-Independent DOM Interfaces
Although the DOM standard grew out of a desire to have a common API for dynamic
to be language-independent. This book describes only the JavaScript binding of the DOM
Although IE 6 claims (through its
hasFeature( ) method) to support the Core and
eHTML interfaces of the DOM Level 1 standard, this support is actually incomplete. Th
most egre
annoying one: IE does not support the node-type constants defined by the No
Recall that each node in a document has a nodeType property that specifies what type o
node it is. The DOM specification also says that the Node interface defines constants th
represent each of the defined node types. For example, the constant Node.ELEMENT
represents an Element node. In IE (at least as high as version 6), these constants simply
The examples in this chapter have been modified to work around this problem by using
integer literals instead of the corresponding symbolic constants. For example, you'll see
code like this:
if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) // Check if n is an Eleme
It is good p
code, and if you'd like to do this portably, you can include the following code in your
if (!window.Node) {
var Nod
ELEMENT_NODE: 1, // with the fo
values.
ATTRIBUTE_NODE: 2, // Note that thes
only.
T
DOCUMENT_FRAGMENT_NODE: 11
}
HTML programming, the DOM is not of interest only to web scripters. In fact, the
standard is currently most heavily used by server-side Java and C++ programs that parse
and manipulate XML documents. Because of its many uses, the DOM standard is defined
API, but you should be aware of a few other points. First, note that object properties in
the JavaScript binding are typically mapped to pairs of get/set methods in other language
bindings. Thus, when a Java programmer asks you about the getFirstChild( ) method
JavaScript binding of the Node
API doesn't define a getFirstChild( ) method. Instead, it simply defines a
firstChild property, and reading the value of this property in JavaScript is equal to
calling getFirstChild( ) in Java.
Another important feature of the JavaScript binding of the DOM API is that certain DOM
objects behave like JavaScript arrays. If an interface defines a method named item( ),
objects that implement that interface behave like read-only numerical arrays. For
example, suppose you've obtained a NodeList object by reading the childNodes property
of a node. You can obtain the individual Node objects in the list by passing the desired
node number to the item( ) method, or, more simply, you can simply treat the NodeList
object as an array and index it directly. The following code illustrates these two options:
var n = document.documentElement; // This is a Node object.
var children = n.childNodes; // This is a NodeList object.
var head = children.item(0); // Here is one way to use a
NodeList.
var body = children[1]; // But this way is easier!
Similarly, if a DOM object has a namedItem( ) method, passing a string to this method
is the same as using the string as an array index for the object. For example, the following
lines of code are all equivalent ways to access a form element:
var f = document.forms.namedItem("myform");
var g = document.forms["myform"];
var h = document.forms.myform;
Because the DOM standard may be used in a variety of ways, the architects of the
standard were careful to define the DOM API in a way that would not restrict the ability
of others to implement the API as they saw fit. Specifically, the DOM standard defines
interfaces instead of classes. In object-oriented programming, a class is a fixed data type
that must be implemented exactly as specified. An interface, on the other hand, is a
collection of methods and properties that must be implemented together. Thus, an
implementation of the DOM is free to define whatever classes it sees fit, but those classes
must define the methods and properties of the various DOM interfaces.
This architecture has a couple of important implications. First, the class names used in an
implementation might not correspond directly to the interface names used in the DOM
standard (and in this book). Second, a single class may implement more than one
interface. For example, consider the Document object. This object is an instance of some
class defined by the web browser implementation. We don't know what the specific class
is, but we do know that it implements the Document interface; that is, all methods and
properties defined by Document are available to us through the Document object. Since
of the Node interface, you need to understand that the
web browsers work with HTML documents, we also know that the Document object
implements the HTMLDocument interface and that all methods and properties defined by
that interface are available to us as well. Furthermore, if a web browser supports CSS
style sheets and implements the DOM CSS module, the Document object also
implements the DocumentStyle and DocumentCSS DOM interfaces. And if the web
browser supports the Events and Views modules, Document implements the
DocumentEvent and DocumentView interfaces as well.
Because the DOM is broken into independent modules, it defines a number of minor add-
on interfaces, such as DocumentStyle, DocumentEvent, and DocumentView, that define
only one or two methods each. Interfaces such as these are never implemented
independently of the core Document interface, and for this reason, I do not document
them independently. When you look up the Document interface in the DOM reference
section, you'll find that it also lists the methods and properties of its various add-on
interfaces. Similarly, if you look up one of the add-on interfaces, you'll simply find a
cross-reference to the core interface with which it is associated. The exception to this rule
is when the add-on interface is a complex one. For example, the HTMLDocument
interface is always implemented by the same object that implements the Document
object, but because it adds substantial new functionality, I have given it a reference page
of its own.
Another important fact you need to understand is that since the DOM standard defines
interfaces instead of classes, it does not define any constructor methods. If you want to
create a new Text object to insert into a document, for example, you cannot simply say:
var t = new Text("this is a new text node"); // No such constructor!
Since it cannot define constructors, the DOM standard instead defines a number of useful
factory methods for creating objects in the Document interface. So, to create a new Text
node for a document, you would write the following:
var t = document.createTextNode("this is a new text node");
Factory methods defined by the DOM have names that begin with the word "create". In
addition to the factory methods defined by Document, a few others are defined by
DOMImplementation and available as
document.implementation.
17.2 Using the Core DOM API
Now that we've studied the tree structure of documents and seen how the tree is
composed of Node objects, we can move on to study the Node object and document trees
in more detail. As I noted previously, the core DOM API is not terribly complex. The
following sections contain examples that demonstrate how you can use it to accomplish
common tasks.
17.2.1 Traversing a Document
As we've already discussed, the DOM represents an HTML document as a tree of Node
objects. With any tree structure, one of the most common things to do is traverse the tree,
examining each node of the tree in turn. Example 17-1 shows one way to do this. It is a
JavaScript function that recursively examines a node and all its children, adding up the
number of HTML tags (i.e., Element nodes) it encounters in the course of the traversal.
Note the use of the childNodes property of a node. The value of this property is a
NodeList object, which behaves (in JavaScript) like an array of Node objects. Thus, the
function can enumerate all the children of a given node by looping through the elements
of the childNodes[] array. By recursing, the function enumerates not just all children of
a given node, but all nodes in the tree of nodes. Note that this function also demonstrates
the use of the nodeType property to determine the type of each node.
Example 17-1. Traversing the nodes of a document
<head>
<script>
// This function is passed a DOM Node object and checks to see if that
e,
s
unters. If you invoke this function by passing it the
ment object, it traverses the entire DOM tree.
untTags(n) { // n is a Node
tags = 0; // Initialize the tag
counter
var children = n.childNodes; // Now get all children
ength; i++) { // Loop through the
children
numtags += countTags(children[i]); // Recurse on each one
}
</script>
</head>
<!-- Here's an example of how the countTags( ) function might be used
-->
<body onload="alert('This document has ' + countTags(document) + '
tags')">
This is a <i>sample</i> document.
</body>
node
// represents an HTML tag; i.e., if the node is an Element object. It
// recursively calls itself on each of the children of the nod
testing
// them in the same way. It returns the total number of Element object
enco// it
Docu//
function co
num var
if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) // Check if n is an
Element
numtags++; // Increment the
counter if so
of n
var i=0; i < children.l for(
}
return numtags; // Return the total
number of tags
Another point to notice about Example 17-1 is that the countTags( ) function it defines
is invoked from the onload event handler, so that it is not called until the document is
completely loaded. This is a general requirement when working with the DOM: you
cannot traverse or manipulate the document tree until the document has been fully
loaded.
op
onstrated in Example 17-2
In addition to the childNodes property, the Node interface defines a few other useful
properties. firstChild and lastChild refer to the first and last children of a node, and
nextSibling and previousSibling refer to adjacent siblings of a node. (Two nodes are
siblings if they have the same parent node.) These properties provide another way to lo
through the children of a node, dem . This example counts the
number of characters in all the Text nodes within the <body> of the document. Notice the
way the countCharacters( ) function uses the firstChild and nextSibling
if that
of the node and adds up the total
length
de
he
t
odeType == 3 /*Node.TEXT_NODE*/) // Check if n is a Text
return n.length; // If so, return its
length
// Otherwise, n may have children whose characters we need to count
var numchars = 0; // Used to hold total characters of the children
// Instead of using the childNodes property, this loop examines the
// children of n using the firstChild and nextSibling properties.
for(var m = n.firstChild; m != null; m = m.nextSibling) {
numchars += countCharacters(m); // Add up total characters
found
}
return numchars; // Return total characters
}
</script>
</head>
<!--
The onload event handler is an example of how the countCharacters( )
function might be used. Note that we want to count only the
properties to loop through the children of a node.
Example 17-2. Another way to traverse a document
<head>
<script>
ect and checks to see // This function is passed a DOM Node obj
node
esents a string of text; i.e., if the node is a Text object. If // repr
// so, it returns the length of the string. If not, it recursively
calls
// itself on each of the children
// of the text it finds. Note that it enumerates the children of a no
// using the firstChild and nextSibling properties. Note also that t
// function does not recurse when it finds a Text node, because Tex
nodes
// never have children.
function countCharacters(n) { // n is a Node
if (n.n
object
characters
in the <body> of the document, so we pass document.body to the
function.
-->
<body onload="alert('Document length: ' +
countCharacters(document.body))">
This is a sample document.<p>How long is it?
</body>
ding Specific Elements in a Document
specific
common to need a particular
Fortunately, the DOM API provides functions that make this easy for us.
17.2.2 Fin
The ability to traverse all nodes in a document tree gives us the power to find
nodes. When programming with the DOM API, it is quite
node within the document or a list of nodes of a specific type within the document.
In Example 17-2, we referred to the <body> element of an HTML document with the
body property of the Document object is a JavaScript expression document.body. The
convenient special-case property and is the preferred way to refer to the <body> tag of an
document. If this convenience property did not exist, however, we could also
This expression calls the Document object's getElementsByTagName( ) method and
lects the first element of the returned array. The call to getElementsByTagName( )
cuments
in the first element of the
HTML
refer to the <body> tag like this:
document.getElementsByTagName("body")[0]
se
returns an array of all <body> elements within the document. Since HTML do
can have only one <body>, we know that we're interested
[6]
returned array.
[6]
Technically, the DOM API specifies that getElementsByTagName( ) returns a NodeList object. In the JavaScript bindin
of the DOM, NodeList objects behave like arrays and are typically used that way.
g
getElementsByTagName( )
For example, to find all the tables within a document, you'd do this:
var tables = document.getElementsByTagName("table");
alert("This document contains " + tables.length + " tables");
Note that since HTML tags are not case-sensitive, the strings passed to
getElementsByTagName( ) are also not case-sensitive. That is, the previous code finds
<table> tags even if they are coded as <TABLE>. getElementsByTagName( ) returns
elements in the order in which they appear in the document. Finally, if you pass the
special string "*" to getElementsByTagName( ), it returns a list of all the elements in
the document, in the order in which they appear. (This special usage is not supported in
You can use to obtain a list of any type of HTML element.
IE 5 and IE 5.5. See instead the IE-specific Document.all[] array in the client-side
reference section.)
Sometimes you don't want a list of elements but instead want to operate on a single
specific element of a document. If you know a lot about the structure of the document,
you may be able to use getElementsByTagName( ). For example, if you want to d
something to the fourth paragraph in a document, you might use this code:
var myParagraph = document.getElementsByTagName("p")[3];
o
the
e for the element. Then you can look up
your desired element by its ID. F might code the special fourth paragraph
graph = document.getElementById("specialParagraph");
rn an array of elements like
every id attribute is (or is
uite
programming.
getElementById( ) and getElementsByTagName( ) are both methods of the
Document object. Element objects also define a method,
t
specific
makes it possible, for example, to
use to find a specific element and then to use
fic
// Find a specific Table element within a document and count its rows
var tableOfContents = document.getElementById("TOC");
This typically is not the best (nor the most efficient) technique, however, because it
depends so heavily on the structure of the document; a new paragraph inserted at
beginning of the document would break the code. Instead, when you need to manipulate
specific elements of a document, it is best to give those elements an id attribute that
specifies a unique (within the document) nam
or example, you
of your document with a tag like this:
<p id="specialParagraph">
You can then look up the node for that paragraph with JavaScript code like this:
var myPara
Note that the getElementById( ) method does not retu
getElementsByTagName( ) does. Because the value of
supposed to be) unique, getElementById( ) returns only the single element with the
matching id attribute. getElementById( ) is an important method, and its use is q
n DOMcommon i
getElementsByTagName( )
however. This method of the Element object behaves just like the method of the
Document object, except that it returns only elements that are descendants of the elemen
on which it is invoked. Instead of searching the entire document for elements of a
type, it searches only within the given element. This
getElementById( )
getElementsByTagName( ) to find all descendants of a given type within that speci
tag. For example:
var rows = tableOfContents.getElementsByTagName("tr");
var numrows = rows.length;