Monday, 9 July 2012

Document Object Model (DOM)

DOM Basics

The Document Object Model (DOM) is perhaps the single greatest innovation on the Web since HTML was first used to connect related documents together over the Internet.The DOM gives developers unprecedented access to HTML,enabling them to manipulate and view HTML as an XML document.The DOM represents the evolution of Dynamic HTML,pioneered by Microsoft and Netscape,into a true cross-platform,language-independent solution.


What Is the DOM? 
 
Before we discuss exactly what the DOM is,we should know what led to its creation.Although the DOM was heavily influenced by the rise of Dynamic HTML in browsers,the W3C took a step backward and first applied it to XML.

Introduction to XML

The eXtensible Markup Language (XML) was derived from an earlier language called Standard Generalized Markup Language(SGML). SGML’s main purpose was to define the syntax of markup languages to represent data using tags.

Tags consist of text enclosed between a less-than symbol(<) and a greater-than symbol(>), as in <tag>.Start tags begin a particular area,such as <start>;end tags define the end of an area.They look the same as start tags but have a forward slash (/) immediately following the less-than symbol,as in </end>.SGML also defines attributes for tags, which are values assigned inside of the less-than and greater-than symbols, such as the src attribute in <img src=”picture.jpg”>.If this looks familiar,it should; the most famous implementation of an SGML-based language is the original HTML.

SGML was used to define the Document Type Definition(DTD) for HTML, and it is still used to write DTDs for XML.The problem with SGML is its allowances for odd syntax, which makes creating parsers for HTML a difficult problem:
  • Some start tags specifically disallow end tags, such as the HTML <img>. Including an end tag causes an error.
  • Some start tags have optional or implied end tags, such as the HTML <p>,which assumes a closing tag when it meets another <p> or several other tags.
  • Some start tags require end tags,such as the HTML <script>.
  • Tags can be embedded in any order.For instance, <b>This is a <i> sample </b> string</i>is okay even though the end tags don’t occur in reverse order of the start tags.
  • Some attributes require values, such as src in <img src=”picture.jpg” >.
  • Some attributes don’t require values, such as nowrap in <td nowrap>.
  • Attribute can be defined with or without quotation marks surrounding them,so <img src=”picture.jpg”> and <img src=picture.jpg> are both allowed.
All these issues make creating SGML language parsers a truly arduous task.The difficultly of knowing when to apply the rules caused a stagnation in the definition of SGML languages.This is where XML begins to fit in.XML does away with all the optional syntax of SGML that caused so many developers heartache early on.In XML, the following rules apply:
  • Every start tag must have end tag.
  • An optional shorthand syntax represents both the start and end tags in one. This syntax uses a forward slash (/) immediately before the greater-than symbol,such as <tag />. An XML parser interprets this as being equal to <tag></tag>.
  • Tags must be embedded in an appropriate order,so end tags must mirror start tags, such as <b>this is a <i> sample </i> string </b>.It helps to think of start and end tags as similar to open and close parentheses in math: You cannot close the outermost parenthesis without first closing all the inner ones.
  • All attributes require values.
  • All attributes must use quotes around the values.
These rules make an XML parser much simpler to develop and also remove the guesswork of when and where to apply odd syntax rules.Where SGML failed to gain mainstream acceptance,XML has made tremendous inroads because of its simplicity. XML has spawned several languages in just the first six years of its existence, including MathML, SVG, RDF, RSS, SOAP, XSLT, XSL-FO, and the reformulation of HTML into XHTML.

Today XML is one of the fastest-growing technologies in the world.Its main purpose is to represent data in a structured way using plain text.In some ways, XML files are not unlike databases,which also represent a structured view of data.Here is an example XML file:

<?xml version=”1.0”?>
<books>
<!--  begin the list of books -->
<book  isbn=”0764543555”>
<title>Professional  JavaScript for Web Developers</title>
<author>Nicholas  C. Zakas</author>
<desc><![CDATA[

Professional JavaScript for Web Developers brings you up to speed on the latest innovations in the world of JavaScript.This book provides you with the details of JavaScript implementations in Web browsers and introduces the new capabilities relating to recently-developed technologies such as XML and Web Services.

]]></desc>
</book>
<?page  render multiple authors ?>
<book  isbn=”0764570773”>
<title>Beginning XML, 3rd Edition</title>
<author>David Hunter</author>
<author>Andrew Watt</author>
<author>Jeff Rafter</author>
<author>Jon Duckett</author>
<author>Danny Ayers</author>
<author>Nicholas Chase</author>
<author>Joe Fawcett</author>
<author>Tom Gaven</author>
<author>Bill Patterson</author>
<desc><![CDATA[

Beginning XML, 3rd Edition, like the first two editions, begins with a broad overview of the technology and then focuses on specific facets of the various specifications for the reader. This book teaches you all you need to know about XML:what it is, how it works, what technologies surround it,and how it can best be used in a variety of situations, from simple data transfer to using XML in your Web pages.It builds on the strengths of the first and second editions, and provides new material to reflect the changes in the XML landscape - notably RSS and SVG.

]]></desc>
</book>
<book  isbn=”0764543555”>
<title>Professional  XML Development with Apache Tools</title>
<author>Theodore  W. Leung</author>
<desc><![CDATA[
If you’re a Java programmer working with XML, you probably already use some of the tools developed by the Apache Software Foundation.This book is a code-intensive guide to the Apache XML tools that are most relevant for Java developers,including Xerces, Xalan, FOP, Cocoon, Axis,and Xindice.
]]></desc>
</book>””””””””
</books>
 
Every XML document begins with the XML prolog, which is the first line in the previous code, <?xml version=”1.0”?>.This line alone tells parsers and browsers that this file should be parsed based on the XML rules discussed earlier. The second line, <books>,is the document element,which is the outermost start tag in the file (an element is considered the contents of a start tag and end tag).All other tags must be contained within this one in order to constitute a valid XML file. The second line of the XML file need not always contain the document element; it can come later if comments or other (???)

The third line in this sample file is a comment, which you may recognize as the same style comment used in HTML. This is one of the syntax elements XML inherited from SGML.

Alittle bit farther down the page you find a <desc> tag with some special syntax inside it.The <![CDATA[ ]]> code is used to indicate text that should not be parsed,allowing special characters such as less-than and greater-than to be included without fear of breaking the XML syntax. The text must appear between <![CDATA[ and ]]> to be properly shielded from parsing. This is called a Character Data Section or  

CData Section for short.

The following line is just before the second book definition:

<?page render multiple authors ?>
 
Even though this looks like the XML prolog, it is actually considered a different type of syntax called a processing instruction. The purpose of processing instructions (or PIs for short) is to provide extra information to programs that are processing the page, such as XML parsers. PIs are generally free form. Their only requirement is that a letter must follow the first question mark. After that point, a PI can contain any sequence of characters aside from the less-than or greater-than symbols.

The most common PI is used to specify a style sheet for an XML file:

<?xml-stylesheet  type=”text/css”” href=”MyStyles.css” ?>

This PI is typically placed immediately after the XML prolog and is used by Web browsers to display the XML data using particular styles.

An API for XML

After XML was defined as a language, the need arose for a way to both represent and manipulate XML code using common programming languages such as Java.

First came the Simple API for XML (SAX) project for Java. SAX provides an event-based API to parse XML. Essentially, SAX parsers start out at the beginning of the file and parse their way through the code in one straight pass, firing events every time it encounters a start tag, end tag, attribute, text, or other XML syntax. It is up to the developer, then, to determine what to do when each of these events occurs.
SAX parsers are lightweight and fast because they just parse the text and continue on their way. Their main downside is the inability to stop, go backward, or access a specific part of the XML structure without starting from the beginning of the file.

The Document Object Model (DOM) is a tree-based API for XML.Its main focus isn’t just to parse XML code, but rather to represent that code using a series of interlinked objects that can be modified and accessed directly without reparsing the code.

Using the DOM, code is parsed once to create a tree model; sometimes a SAX parser is used to accomplish this. After that initial parse,the XML is fully represented in a DOM model, and the original code is no longer needed. Although the DOM is slower than SAX and requires more overhead because it creates so many objects,it is the method favored by Web browsers and JavaScript for its ease of use.

Hierarchy of nodes

So what exactly is a tree-based API? When talking about DOM trees (which are called documents),you are really talking about a hierarchy of nodes. The DOM defines the Node interface as well as a large number of node types to represent the multiple aspects of XML code:
  • Document — The very top-level node to which all other nodes are attached
  • DocumentType — The object representation of a DTD reference using the syntax <!DOCTYPE >, such as <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>. It cannot contain child nodes.
  • DocumentFragment — Can be used like a Document to hold other nodes
  • Element — Represents the contents of a start tag and end tag, such as <tag></tag> or <tag/>. This node type is the only one that can contain attributes as well as child nodes.
  • Attr — Represents an attribute name-value pair. This node type cannot have child nodes.
  • Text — Represents plain text in an XML document contained within start and end tags or inside of a CData Section.This node type cannot have child nodes.
  • CDataSection — The object representation of <![CDATA[ ]]>. This node type can have only text nodes as child nodes.
  • Entity — Represents an entity definition in a DTD, such as <!ENTITY foo “foo”>. This node type cannot have child nodes.
  • EntityReference — Represents an entity reference, such as &quot;. This node type cannot have child nodes.
  • ProcessingInstruction — Represents a PI. This node type cannot have child nodes.
  • Comment — Represents an XML comment. This node type cannot have child nodes.
  • Notation — Represents notation defined in a DTD. This is rarely used .
A document is made up of a hierarchy of any number of these nodes. Consider the following XML code:
 
<?xml  version=”1.0”?>
<employees>
<!--  only employee -->
<employee>
<name>Michael  Smith</name>
<position>Software  Engineer</position>
<comments><![CDATA[
His  birthday is on 8/14/68.
]]></comments>
</employee>””
</employees>

This code can be represented in a DOM document as displayed each rectangle represents a node in the DOM document tree, with the bold text indicating the node type and the nonbold text indicating the content of that node.


Both the comment and <employee/> nodes are considered to be child nodes of <employees/> because they fall immediately underneath it in the tree.Likewise, <employees/> is considered the parent node of the comment and <employee/> nodes.

Similarly,<name/>, <position/>,and <comments/> are all considered child nodes of <employee/> and are also considered siblings of each other because they exist at the same level of the DOM tree and have the same parent node.

The <employees/> node is considered the ancestor of all nodes in this section of the tree, including its children (the comment and <employee/>) as well as their children (<name/>, <position/>, and so on, all the way down to the text node “His birthday is on 8/14/68”). The document node is considered the ancestor of all nodes in the document. The Node interface defines 12 constants that map to the different node types
  • Node.ELEMENT_NODE (1)
  • Node.ATTRIBUTE_NODE (2)
  • Node.TEXT_NODE (3)
  • Node.CDATA_SECTION_NODE (4)
  • Node.ENTITY_REFERENCE_NODE (5)
  • Node.ENTITY_NODE (6)
  • Node.PROCESSING_INSTRUCTION_NODE (7)
  • Node.COMMENT_NODE (8)
  • Node.DOCUMENT_NODE (9)
  • Node.DOCUMENT_TYPE_NODE (10)
  • Node.DOCUMENT_FRAGMENT_NODE (11)
  • Node.NOTATION_NODE (12)
The Node interface also defines a set of properties and methods that all node types contain. These properties and methods are listed out in the following table:



In addition to nodes,the DOM also defines some helper objects, which are used to work with nodes but are not necessarily part of a DOM document:
  • NodeList — an array of nodes indexed numerically; used to represent child nodes of an element
  • NamedNodeMap — an array of nodes indexed both numerically and name; used to represent element attributes

These helper objects provide additional access and traversal methods for dealing with DOM document.

Language-Specific DOMs

Any XML-based language,such as XHTML and SVG, can make use of the core DOM just introduced because they are technically XML.However,many languages go on to define their own DOMs that extend the XML core to provide language-specific features.

Along with developing the XML DOM,the W3C concurrently developed a DOM more specific to XHTML (and HTML). This DOM defines an HTMLDocument and HTMLElement as the basis for the implementation.Each HTML element is represented by its own HTMLElement type,such as HTMLDivElement representing <div>,with the exception of a small subset of elements that don’t require special properties or methods other than those provided by HTML Element.

DOM Support 
 
All browsers are not at the same level of DOM support.Generally speaking, Mozilla has the best DOM standards support,supporting almost all DOM Level 2 and parts of DOM Level 3. Behind Mozilla,Opera and Safari have made significant inroads toward closing the support gap,supporting almost all DOM Level 1 and most of DOM Level 2.Lagging behind the field is Internet Explorer,whose incomplete implementation of DOM Level 1 leaves much to be desired.

Using the DOM 
 
Even though the document object is considered part of the BOM, it is also is a representation of the HTML DOM’s HTMLDocument object,which, in turn,is also an XML DOM Document object.Most DOM manipulation in JavaScript makes use of the document object,so that’s a logical place to begin the discussion.
Accessing relative nodes

Consider the following HTML page for the next few sections:

<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<p>Hello  World!</p>
<p>Isn’t  this exciting?</p>
<p>You’re  learning to use the DOM!</p>
</body>
</html>
 
To access the <html/> element(which you should realize is the document element of this file),you can use the documentElement property of document:

var oHtml = document.documentElement;


The variable oHtml now contains an HTMLElement object representing <html/>.If you want to get the <head/> and <body/>elements using oHtml, this works:

var oHead = oHtml.firstChild;
var oBody = oHtml.lastChild;
 
You can also use the childNodes property to accomplish the same thing.Just pretend that it’s a regular JavaScript Array and use square-bracket notation:

var oHead = oHtml.childNodes[0];
var oBody = oHtml.childNodes[1];
 
You can also get the number of child nodes by using the childNodes.length property:

alert(oHtml.childNodes.length); //outputs “2”

Note that the square-bracket notation is a convenient implementation of the NodeList in JavaScript.The formal method of retrieving child nodes from the childNodes list is the item() method:

var oHead = oHtml.childNodes.item(0);
var oBody = oHtml.childNodes.item(1);
 
The HTML DOM also defines document.body as a pointer to the <body /> element:
var oBody = document.body;
 
With the three variables oHtml,oHead, and oBody,you can play around to determine their relationship to one another:

alert(oHead.parentNode  == oHtml); //outputs “true”
alert(oBody.parentNode  == oHtml); //outputs “true”
alert(oBody.previousSibling  == oHead); //outputs “true”
alert(oHead.nextSibling  == oBody); //outputs “true”
alert(oHead.ownerDocument  == document); //outputs “true”
 
This little snippet of code tests to make sure that the parentNode property of both oBody and oHead point to oHtml,as well as uses the previousSibling and nextSibling properties to establish their relationship to one another.The last line assures that the ownerDocument property of oHead actually does point back to the document.

Checking the node type

You can check the type of node by using the nodeType property:
alert(document.nodeType);  //outputs “9”
alert(document.documentElement.nodeType);  //outputs “1”
 
In this example,document.nodeType returns 9,which is equal to Node.DOCUMENT_NODE, and  document.documentElement.nodeType returns 1, which is equal to Node.ELEMENT_NODE.

You can also match up these values with the Node constants:

alert(document.nodeType  == Node.DOCUMENT_NODE); //outputs “true”
alert(document.documentElement.nodeType  == Node.ELEMENT_NODE); //outputs “true”
This code works in Mozilla 1.0+, Opera 7.0+, and Safari 1.0+. Unfortunately,Internet Explorer doesn’t support these constant values,so this code causes an error.You can remedy the situation by defining your own constants that match the node type constants,such as the following:
if(typeof Node == “undefined”) {
var Node = {
ELEMENT_NODE:  1,
ATTRIBUTE_NODE:  2,
TEXT_NODE:  3,
CDATA_SECTION_NODE:  4,
ENTITY_REFERENCE_NODE:  5,
ENTITY_NODE:  6,
PROCESSING_INSTRUCTION_NODE:  7,
COMMENT_NODE:  8,
DOCUMENT_NODE:  9,
DOCUMENT_TYPE_NODE:  10,
DOCUMENT_FRAGMENT_NODE:  11,
NOTATION_NODE:  12
}
}
The other option is to use the integer literals(although this may get confusing because not many people have memorized the node type values).
Dealing with attributes
As mentioned previously, only Element nodes have attributes even though the Node interface has an attributes method that is inherited by all node types. The attributes property for an Element node is a NamedNodeMap,which provides several methods for accessing and manipulating its contents:
  • getNamedItem(name) — returns the node whose nodeName property is equal to name
  • removeNamedItem(name) — removes the node whose nodeName property is equal to name from the list
  • setNamedItem(node) — adds the nodeinto the list,indexing it by its nodeName property
  • item(pos) — just like NodeList,returns the node in the numerical position pos
The NamedNodeMap object also has a length property to indicate the number of nodes it contains.
When used to represent attributes,each node in the NamedNodeMap is an Attr node, whose nodeName property is set to the attribute name. The nodeValue property is set to the attribute value. For example,suppose you had this element:
<p> style=”color: red” id=”p1”>Hello world!</p>
Also, uppose that the variable oP that contains a reference to this element.You can access the value of the id attribute like this:
var sId = oP.attributes.getNamedItem(“id”).nodeValue;
Of course,you could access this id attribute numerically, which is a little less intuitive:
var sId = oP.attributes.item(1).nodeValue;
You can change the id attribute by setting a new value to the nodeValue property:
oP.attributes.getNamedItem(“id”).nodeValue  = “newId”; 
Attr nodes also have a value property that is exactly equal (and kept in sync with) the nodeValue property, as well as a name property that is kept in sync with nodeName. You use any of these properties to modify or change the attributes.
Because this method is a little bit cumbersome, the DOM also defines three element methods to aid in the assignment of attributes:
  • getAttribute(name) — same as attributes.getNamedItem(name).value
  • setAttribute(name, newvalue) — same as attributes.getNamedItem(name).value = newvalue
  • removeAttribute(name) — same as attributes.removeNamedItem(name)
These methods are helpful in that they deal directly with the attribute values,completely hiding the Attr nodes.So, to retrieve the id attribute of the <p /> used earlier, you can just do this:
var sId = oP.getAttribute(“id”);
And to change the ID, you can do this:
oP.setAttribute(“id”, “newId”);
As you can see, these methods are much less verbose than using the NamedNodeMap methods.
Accessing specific nodes
You already know how to access parent and child nodes,but what if you want access to a node (or group of nodes) that are located deep in the document? Certainly,you don’t want to count child nodes until you get down to what you’re looking for. To help you in this use case, the DOM provides several methods to enable easy access to specific nodes.

getElementsByTagName()

The Core (XML) DOM defines the method getElementsByTagName()to return a NodeList of all Element objects whose tagName property is equal to a specific value.In an Element object, the tagName property is always equal to the name immediately following the less-than symbol — for example, the tagName of <img /> is “img”.The following line of code returns a list of all <img /> elements in a document:
var oImgs = document.getElementsByTagName(“img”);
After storing all of the images in oImgs, you can access them individually in the same way that you access child nodes, by using either square-bracket notation or the item() method (getElementsByTagName() returns a NodeList,just like childNodes):
alert(oImgs[0].tagName);//outputs “IMG”
This line of code outputs the tagName of the first image, which is output as “IMG”. For some reason, most browsers still record the tag name as all uppercase even though XHTML conventions dictate that tag names must be all lowercase.
But suppose you want to get only the images within the first paragraph of a page.This can be accomplished by calling getElementsByTagName() on the first paragraph elementlike this:
var oPs = document.getElementsByTagname(“p”);
var oImgsInP = oPs[0].getElementsByTagName(“img”);
You can use this one method to get down to any element in the document or to get all elements in the document by using an asterisk:
var oAllElements = document.getElementsByTagName(“*”);
This line of code returns all the elements contained in document regardless of their tag names.
getElementsByName()
The HTML DOM defines getElementsByName() to retrieve all elements that have their name attributeset to a specific value. Consider the following HTML:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<form  method=”post” action=”dosomething.cgi”>
<fieldset>
<legend>What  color do you like?</legend>
<input type=”radio” name=”radColor” value=”red” /> Red<br />
<input type=”radio” name=”radColor” value=”green” /> Green<br />
<input type=”radio” name=”radColor” value=”blue” /> Blue<br />
</fieldset>
<input type=”submit” value=”Submit” />
</form>
</body>
</html>
This page asks the user which color he/she likes.The radio buttons all have the same name,because you only want to return one value for this field, which is the value attribute of the selected radio button. To get references to all the radio button elements, you can use the following code:
var oRadios = document.getElementsByName(“radColor”);
You can then manipulate the radio buttons the same way as you can any other element:
alert(oRadios[0].getAttribute(“value”));  //outputs “red”
getElementById()
The second method defined by the HTML DOM is getElementById(),which returns an element with its id attribute set to a specific value.In HTML, the id attribute is unique—meaning that no two elements can share the same id. This is undoubtedly the fastest method of retrieving a single specific element from the document tree. Suppose you have the following HTML page:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<p>Hello  World!</p>
<div  id=”div1”>This is my first layer</div>
</body>
</html>
To access the <div /> element with the ID “div1”, you can use the getElementsByTagName() like this:
var oDivs = document.getElementsByTagName(“div”);
var oDiv1 = null;
for(var i=0; i < oDivs.length; i++){
if  (oDivs[i].getAttribute(“id”) == “div1”) {
oDiv1 = oDivs[i];
break;
}
}
Or,you could use getElementById() like this:
var oDiv1 = document.getElementById(“div1”);
As you can see, this is a much more streamlined way to get a reference to a specific element.
Creating and manipulating nodes
So far, you’ve learned how to access various nodes inside of a document, but that’s just the beginning of what can be done using the DOM. You can also add,remove,replace, and otherwise manipulate nodes within a DOM document. This functionality is what makes the DOM truly dynamic.
Creating new nodes
The DOM Document has a number of methods designed to create various types of nodes,even though the browser document object doesn’t necessarily support each of these methods in all browsers. The following table lists the methods included in DOM Level 1 and which browsers support each other.

The most commonly used methods are createDocumentFragment(),createElement(), and createTextNode(); the other methods are either not useful (createComment()) or not supported by enough browsers to be useful at this point in time.
createElement(),createTextNode(),appendChild()
Suppose you have the following HTML page:
<html>
<head>
<title>createElement()  Example</title>
</head>
<body>
</body>
</html>
To this page, you want to add the following code using the DOM:
<p>Hello  World!</p>
The createElement() and createTextNode() methods can be used to accomplish this. Here’s how.
The first thing to do is create the <p/> element:
var oP = document.createElement(“p”);
Second, create the text node:
var oText = document.createTextNode(“Hello World!”);
Next you need to add the text node to the element. To do this, you can use the appendChild() method,which was briefly mentioned earlier in the chapter. The appendChild() method exists on every node type and is used to add a given node to the end of another’s childNodes list. In this case, the text node should be added to the <p /> element:
oP.appendChild(oText);
You’re not done quite yet.You have created the element and text node and attached them to each other, but the element still doesn’t have a spot in the document.To actually be visible, the element must be attached either to the document.body element or one of its children. Once again, you can use the appendChild() method for this:
document.body.appendChild(oP);
To put all this into a sample you can run,just create a function containing each of these steps and call it when the page is loaded by using the onload event handler.
<html>
<head>
<title>createElement()  Example</title>
<script type=”text/javascript”>
function createMessage() {
var oP = document.createElement(“p”);
var oText = document.createTextNode(“Hello World! “);
oP.appendChild(oText);
document.body.appendChild(oP);
}
</script>
</head>
<body  onload=”createMessage()”>
</body>
</html>
When you run this code,the message “Hello World!” is displayed as if it were part of the HTML document all along.
removeChild(),replaceChild(), and insertBefore()
Naturally,if you can add a node you can also remove a node, which is where the removeChild() method comes in. This method accepts one argument,the node to remove,and then returns that node as the function value.So if, for instance, you start out with a page already containing the “Hello World!” message and you wanted to remove it, you can use the method like this:
<html>
<head>
<title>removeChild()  Example</title>
<script  type=”text/javascript”>
function  removeMessage() {
var  oP = document.body.getElementsByTagName(“p”)[0];
document.body.removeChild(oP);
}
</script>
</head>
<body  onload=”removeMessage()”>
<p>Hello  World!</p>
</body>
</html>
When this page is loaded,it displays a blank screen because the message is removed even before you have a chance to see it. Although this works, it’s always better to use a node’s parentNode property to make sure you are accessing its real parent:
<html>
<head>
<title>removeChild()  Example</title>
<script type=”text/javascript”>
function removeMessage() {
var  oP = document.body.getElementsByTagName(“p”)[0];
oP.parentNode.removeChild(oP);
}
</script>
</head>
<body onload=”replaceMessage()”>
<p>Hello  World!</p>
</body>
</html>
But what if you want to replace this message with a new one? In that case, you can use the replaceChild() method. The replaceChild() method takes two arguments: the node to add and the node to replace. In this case, you create a new element with a new message and replace the <p /> element with the “Hello World!” message.
<html>
<head>
<title>replaceChild()  Example</title>
<script type=”text/javascript”>
function replaceMessage() {
var oNewP = document.createElement(“p”);
var oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
var oOldP = document.body.getElementsByTagName(“p”)[0];
oOldP.parentNode.replaceChild(oNewP,  oOldP);
}
</script>
</head>
<body  onload=”replaceMessage()”>
<p>Hello  World!</p>
</body>
</html>
This sample page replaces the message “Hello World!” with “Hello Universe!” Note that this code still uses the parentNode property to ensure the correct parent is being manipulated. Of course,you may want both messages to appear.If you want the new message to come after the old message,use the appendChild() method:
<html>
<head>
<title>appendChild()  Example</title>
<script  type=”text/javascript”>
function  appendMessage() {
var  oNewP = document.createElement(“p”);
var  oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
document.body.appendChild(oNewP);
}
</script>
</head>
<body  onload=”appendMessage()”>
<p>Hello  World!</p>
</body>
</html>
If,however,you want the new message to come before the old, use the insertBefore() method.This method accepts two arguments: the new node to add and the node that it should be inserted before.In this example, the second argument is the <p /> element containing “Hello World!”:
<html>
<head>
<title>insertBefore()  Example</title>
<script type=”text/javascript”>
function insertMessage() {
var oNewP = document.createElement(“p”);
var oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
var oOldP = document.getElementsByTagName(“p”)[0];
document.body.insertBefore(oNewP,  oOldP);
}
</script>
</head>
<body  onload=”insertMessage()”>
<p>Hello  World!</p>
</body>
</html>
createDocumentFragment()
As soon as you add nodes to document.body (or one of its ancestors), the page is updated to reflect the changes. This is fine for a small number of changes, as in the previous examples.However, when a large amount of data has to be added to the document, it can be a very slow process if it adds changes one-byone.
To correct this situation, you can create a document fragment to which you attach all new nodes, and then add the contents of the document fragment to the document. Suppose you want to create ten new paragraphs.Using the methods you learned previously, you write this code:
var arrText = [“first”,“second”,“third”,“fourth”,“fifth”,“sixth”,“seventh”,
“eighth”, “ninth”, “tenth”];
for (var i=0; i < arrText.length; i++) {
var oP = document.createElement(“p”);
var oText = document.createTextNode(arrText[i]);
oP.appendChild(oText);
document.body.appendChild(oP);}
This code works just fine, the problem is that it’s making ten calls to document.body.appendChild(),which causes a refresh of the page each time. This is where the document fragment is useful:
va  arrText = [“first”, “second”,“third”,“fourth”,“fifth”,“sixth”,“seventh”,
“eighth”, “ninth”, “tenth”];
var oFragment = document.createDocumentFragment();
for(var i=0; i < arrText.length; i++) {
var oP = document.createElement(“p”);
var oText = document.createTextNode(arrText[i]);
oP.appendChild(oText);
oFragment.appendChild(oP);
}
document.body.appendChild(oFragment);
In this code, each new <p /> element is added to the document fragment. Then,the fragment is passed in as the argument to appendChild().The call to appendChild() doesn’t actually append the document fragment node itself to the <body /> element; instead, it just appends the fragment’s child nodes. You can see the obvious performance gains: One call to document.body.appendChild() instead of 10 means only one screen refresh.
Even though the document object is considered part of the BOM, it is also is a representation of the HTML DOM’s HTMLDocument object,which, in turn,is also an XML DOM Document object.Most DOM manipulation in JavaScript makes use of the document object,so that’s a logical place to begin the discussion.
Accessing relative nodes
Consider the following HTML page for the next few sections:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<p>Hello  World!</p>
<p>Isn’t  this exciting?</p>
<p>You’re  learning to use the DOM!</p>
</body>
</html>
To access the <html/> element(which you should realize is the document element of this file),you can use the documentElement property of document:
var oHtml = document.documentElement;
The variable oHtml now contains an HTMLElement object representing <html/>.If you want to get the <head/> and <body/>elements using oHtml, this works:
var oHead = oHtml.firstChild;
var oBody = oHtml.lastChild;
You can also use the childNodes property to accomplish the same thing.Just pretend that it’s a regular JavaScript Array and use square-bracket notation:
var oHead = oHtml.childNodes[0];
var oBody = oHtml.childNodes[1];
You can also get the number of child nodes by using the childNodes.length property:
alert(oHtml.childNodes.length); //outputs “2”
Note that the square-bracket notation is a convenient implementation of the NodeList in JavaScript.The formal method of retrieving child nodes from the childNodes list is the item() method:
var oHead = oHtml.childNodes.item(0);
var oBody = oHtml.childNodes.item(1);
The HTML DOM also defines document.body as a pointer to the <body /> element:
var oBody = document.body;
With the three variables oHtml,oHead, and oBody,you can play around to determine their relationship to one another:
alert(oHead.parentNode  == oHtml); //outputs “true”
alert(oBody.parentNode  == oHtml); //outputs “true”
alert(oBody.previousSibling  == oHead); //outputs “true”
alert(oHead.nextSibling  == oBody); //outputs “true”
alert(oHead.ownerDocument  == document); //outputs “true”
This little snippet of code tests to make sure that the parentNode property of both oBody and oHead point to oHtml,as well as uses the previousSibling and nextSibling properties to establish their relationship to one another.The last line assures that the ownerDocument property of oHead actually does point back to the document.
Checking the node type
You can check the type of node by using the nodeType property:
alert(document.nodeType);  //outputs “9”
alert(document.documentElement.nodeType);  //outputs “1”
In this example,document.nodeType returns 9,which is equal to Node.DOCUMENT_NODE, and  document.documentElement.nodeType returns 1, which is equal to Node.ELEMENT_NODE.
You can also match up these values with the Node constants:
alert(document.nodeType  == Node.DOCUMENT_NODE); //outputs “true”
alert(document.documentElement.nodeType  == Node.ELEMENT_NODE); //outputs “true”
This code works in Mozilla 1.0+, Opera 7.0+, and Safari 1.0+. Unfortunately,Internet Explorer doesn’t support these constant values,so this code causes an error.You can remedy the situation by defining your own constants that match the node type constants,such as the following:
if(typeof Node == “undefined”) {
var Node = {
ELEMENT_NODE:  1,
ATTRIBUTE_NODE:  2,
TEXT_NODE:  3,
CDATA_SECTION_NODE:  4,
ENTITY_REFERENCE_NODE:  5,
ENTITY_NODE:  6,
PROCESSING_INSTRUCTION_NODE:  7,
COMMENT_NODE:  8,
DOCUMENT_NODE:  9,
DOCUMENT_TYPE_NODE:  10,
DOCUMENT_FRAGMENT_NODE:  11,
NOTATION_NODE:  12
}
}
The other option is to use the integer literals(although this may get confusing because not many people have memorized the node type values).
Dealing with attributes
As mentioned previously, only Element nodes have attributes even though the Node interface has an attributes method that is inherited by all node types. The attributes property for an Element node is a NamedNodeMap,which provides several methods for accessing and manipulating its contents:
  • getNamedItem(name) — returns the node whose nodeName property is equal to name
  • removeNamedItem(name) — removes the node whose nodeName property is equal to name from the list
  • setNamedItem(node) — adds the nodeinto the list,indexing it by its nodeName property
  • item(pos) — just like NodeList,returns the node in the numerical position pos
The NamedNodeMap object also has a length property to indicate the number of nodes it contains.
When used to represent attributes,each node in the NamedNodeMap is an Attr node, whose nodeName property is set to the attribute name. The nodeValue property is set to the attribute value. For example,suppose you had this element:
<p> style=”color: red” id=”p1”>Hello world!</p>
Also, uppose that the variable oP that contains a reference to this element.You can access the value of the id attribute like this:
var sId = oP.attributes.getNamedItem(“id”).nodeValue;
Of course,you could access this id attribute numerically, which is a little less intuitive:
var sId = oP.attributes.item(1).nodeValue;
You can change the id attribute by setting a new value to the nodeValue property:
oP.attributes.getNamedItem(“id”).nodeValue  = “newId”; 
Attr nodes also have a value property that is exactly equal (and kept in sync with) the nodeValue property, as well as a name property that is kept in sync with nodeName. You use any of these properties to modify or change the attributes.
Because this method is a little bit cumbersome, the DOM also defines three element methods to aid in the assignment of attributes:
  • getAttribute(name) — same as attributes.getNamedItem(name).value
  • setAttribute(name, newvalue) — same as attributes.getNamedItem(name).value = newvalue
  • removeAttribute(name) — same as attributes.removeNamedItem(name)
These methods are helpful in that they deal directly with the attribute values,completely hiding the Attr nodes.So, to retrieve the id attribute of the <p /> used earlier, you can just do this:
var sId = oP.getAttribute(“id”);
And to change the ID, you can do this:
oP.setAttribute(“id”, “newId”);
As you can see, these methods are much less verbose than using the NamedNodeMap methods.
Accessing specific nodes
You already know how to access parent and child nodes,but what if you want access to a node (or group of nodes) that are located deep in the document? Certainly,you don’t want to count child nodes until you get down to what you’re looking for. To help you in this use case, the DOM provides several methods to enable easy access to specific nodes.

getElementsByTagName()

The Core (XML) DOM defines the method getElementsByTagName()to return a NodeList of all Element objects whose tagName property is equal to a specific value.In an Element object, the tagName property is always equal to the name immediately following the less-than symbol — for example, the tagName of <img /> is “img”.The following line of code returns a list of all <img /> elements in a document:
var oImgs = document.getElementsByTagName(“img”);
After storing all of the images in oImgs, you can access them individually in the same way that you access child nodes, by using either square-bracket notation or the item() method (getElementsByTagName() returns a NodeList,just like childNodes):
alert(oImgs[0].tagName);  //outputs “IMG”
This line of code outputs the tagName of the first image, which is output as “IMG”. For some reason, most browsers still record the tag name as all uppercase even though XHTML conventions dictate that tag names must be all lowercase.
But suppose you want to get only the images within the first paragraph of a page.This can be accomplished by calling getElementsByTagName() on the first paragraph elementlike this:
var oPs = document.getElementsByTagname(“p”);
var oImgsInP = oPs[0].getElementsByTagName(“img”);
You can use this one method to get down to any element in the document or to get all elements in the document by using an asterisk:
var oAllElements = document.getElementsByTagName(“*”);
This line of code returns all the elements contained in document regardless of their tag names.
getElementsByName()
The HTML DOM defines getElementsByName() to retrieve all elements that have their name attributeset to a specific value. Consider the following HTML:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<form  method=”post” action=”dosomething.cgi”>
<fieldset>
<legend>What  color do you like?</legend>
<input type=”radio” name=”radColor” value=”red” /> Red<br />
<input type=”radio” name=”radColor” value=”green” /> Green<br />
<input type=”radio” name=”radColor” value=”blue” /> Blue<br />
</fieldset>
<input type=”submit” value=”Submit” />
</form>
</body>
</html>
This page asks the user which color he/she likes.The radio buttons all have the same name,because you only want to return one value for this field, which is the value attribute of the selected radio button. To get references to all the radio button elements, you can use the following code:
var oRadios = document.getElementsByName(“radColor”);
You can then manipulate the radio buttons the same way as you can any other element:
alert(oRadios[0].getAttribute(“value”));  //outputs “red”
getElementById()
The second method defined by the HTML DOM is getElementById(),which returns an element with its id attribute set to a specific value.In HTML, the id attribute is unique—meaning that no two elements can share the same id. This is undoubtedly the fastest method of retrieving a single specific element from the document tree. Suppose you have the following HTML page:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<p>Hello  World!</p>
<div  id=”div1”>This is my first layer</div>
</body>
</html>
To access the <div /> element with the ID “div1”, you can use the getElementsByTagName() like this:
var oDivs = document.getElementsByTagName(“div”);
var oDiv1 = null;
for(var i=0; i < oDivs.length; i++){
if  (oDivs[i].getAttribute(“id”) == “div1”) {
oDiv1 = oDivs[i];
break;
}
}
Or,you could use getElementById() like this:
var oDiv1 = document.getElementById(“div1”);
As you can see, this is a much more streamlined way to get a reference to a specific element.
Creating and manipulating nodes
So far, you’ve learned how to access various nodes inside of a document, but that’s just the beginning of what can be done using the DOM. You can also add,remove,replace, and otherwise manipulate nodes within a DOM document. This functionality is what makes the DOM truly dynamic.
Creating new nodes
The DOM Document has a number of methods designed to create various types of nodes,even though the browser document object doesn’t necessarily support each of these methods in all browsers. The following table lists the methods included in DOM Level 1 and which browsers support each other.

The most commonly used methods are createDocumentFragment(),createElement(), and createTextNode(); the other methods are either not useful (createComment()) or not supported by enough browsers to be useful at this point in time.
createElement(),createTextNode(),appendChild()
Suppose you have the following HTML page:
<html>
<head>
<title>createElement()  Example</title>
</head>
<body>
</body>
</html>
To this page, you want to add the following code using the DOM:
<p>Hello  World!</p>
The createElement() and createTextNode() methods can be used to accomplish this. Here’s how.
The first thing to do is create the <p/> element:
var oP = document.createElement(“p”);
Second, create the text node:
var oText = document.createTextNode(“Hello World!”);
Next you need to add the text node to the element. To do this, you can use the appendChild() method,which was briefly mentioned earlier in the chapter. The appendChild() method exists on every node type and is used to add a given node to the end of another’s childNodes list. In this case, the text node should be added to the <p /> element:
oP.appendChild(oText);
You’re not done quite yet.You have created the element and text node and attached them to each other, but the element still doesn’t have a spot in the document.To actually be visible, the element must be attached either to the document.body element or one of its children. Once again, you can use the appendChild() method for this:
document.body.appendChild(oP);
To put all this into a sample you can run,just create a function containing each of these steps and call it when the page is loaded by using the onload event handler.
<html>
<head>
<title>createElement()  Example</title>
<script type=”text/javascript”>
function createMessage() {
var oP = document.createElement(“p”);
var oText = document.createTextNode(“Hello World! “);
oP.appendChild(oText);
document.body.appendChild(oP);
}
</script>
</head>
<body  onload=”createMessage()”>
</body>
</html>
When you run this code,the message “Hello World!” is displayed as if it were part of the HTML document all along.
removeChild(),replaceChild(), and insertBefore()
Naturally,if you can add a node you can also remove a node, which is where the removeChild() method comes in. This method accepts one argument,the node to remove,and then returns that node as the function value.So if, for instance, you start out with a page already containing the “Hello World!” message and you wanted to remove it, you can use the method like this: 
<html>
<head>
<title>removeChild()  Example</title>
<script  type=”text/javascript”>
function  removeMessage() {
var  oP = document.body.getElementsByTagName(“p”)[0];
document.body.removeChild(oP);
}
</script>
</head>
<body  onload=”removeMessage()”>
<p>Hello  World!</p>
</body>
</html>
When this page is loaded,it displays a blank screen because the message is removed even before you have a chance to see it. Although this works, it’s always better to use a node’s parentNode property to make sure you are accessing its real parent:
<html>
<head>
<title>removeChild()  Example</title>
<script type=”text/javascript”>
function removeMessage() {
var  oP = document.body.getElementsByTagName(“p”)[0];
oP.parentNode.removeChild(oP);
}
</script>
</head>
<body  onload=”replaceMessage()”>
<p>Hello  World!</p>
</body>
</html>
But what if you want to replace this message with a new one? In that case, you can use the replaceChild() method. The replaceChild() method takes two arguments: the node to add and the node to replace. In this case, you create a new element with a new message and replace the <p /> element with the “Hello World!” message.
<html>
<head>
<title>replaceChild()  Example</title>
<script type=”text/javascript”>
function replaceMessage() {
var oNewP = document.createElement(“p”);
va  oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
var  oOldP = document.body.getElementsByTagName(“p”)[0];
oOldP.parentNode.replaceChild(oNewP,  oOldP);
}
</script>
</head>
<body onload=”replaceMessage()”>
<p>Hello World!</p>
</body>
</html>
This sample page replaces the message “Hello World!” with “Hello Universe!” Note that this code still uses the parentNode property to ensure the correct parent is being manipulated. Of course,you may want both messages to appear.If you want the new message to come after the old message,use the appendChild() method:
<html>
<head>
<title>appendChild() Example</title>
<script type=”text/javascript”>
function appendMessage() {
var oNewP = document.createElement(“p”);
var oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
document.body.appendChild(oNewP);
}
</script>
</head>
<body  onload=”appendMessage()”>
<p>Hello  World!</p>
</body>
</html>
If,however,you want the new message to come before the old, use the insertBefore() method.This method accepts two arguments: the new node to add and the node that it should be inserted before.In this example, the second argument is the <p /> element containing “Hello World!”:
<html>
<head>
<title>insertBefore()  Example</title>
<script  type=”text/javascript”>
function  insertMessage() {
var oNewP = document.createElement(“p”);
var oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
var oOldP = document.getElementsByTagName(“p”)[0];
document.body.insertBefore(oNewP,  oOldP);
}
</script>
</head>
<body onload=”insertMessage()”>
<p>Hello World!</p>
</body>
</html>
createDocumentFragment()
As soon as you add nodes to document.body (or one of its ancestors), the page is updated to reflect the changes. This is fine for a small number of changes, as in the previous examples.However, when a large amount of data has to be added to the document, it can be a very slow process if it adds changes one-byone.
To correct this situation, you can create a document fragment to which you attach all new nodes, and then add the contents of the document fragment to the document. Suppose you want to create ten new paragraphs.Using the methods you learned previously, you write this code:
var  arrText = [“first”,“second”,“third”,“fourth”,“fifth”,“sixth”,“seventh”,
“eighth”,  “ninth”, “tenth”];
for (var i=0; i < arrText.length; i++) {
var oP = document.createElement(“p”);
var oText = document.createTextNode(arrText[i]);
oP.appendChild(oText);
document.body.appendChild(oP);}
This code works just fine, the problem is that it’s making ten calls to document.body.appendChild(),which causes a refresh of the page each time. This is where the document fragment is useful:
var arrText = [“first”,“second”,“third”,“fourth”,“fifth”,“sixth”,“seventh”,
“eighth”,  “ninth”, “tenth”];
var oFragment = document.createDocumentFragment();
for(var i=0; i < arrText.length; i++) {
var oP = document.createElement(“p”);
var oText = document.createTextNode(arrText[i]);
oP.appendChild(oText);
oFragment.appendChild(oP);
}
document.body.appendChild(oFragment);
In this code, each new <p /> element is added to the document fragment. Then,the fragment is passed in as the argument to appendChild().The call to appendChild() doesn’t actually append the document fragment node itself to the <body /> element; instead, it just appends the fragment’s child nodes. You can see the obvious performance gains: One call to document.body.appendChild() instead of 10 means only one screen refresh.
Even though the document object is considered part of the BOM, it is also is a representation of the HTML DOM’s HTMLDocument object,which, in turn,is also an XML DOM Document object.Most DOM manipulation in JavaScript makes use of the document object,so that’s a logical place to begin the discussion.
Accessing relative nodes
Consider the following HTML page for the next few sections:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<p>Hello  World!</p>
<p>Isn’t  this exciting?</p>
<p>You’re  learning to use the DOM!</p>
</body>
</html>
To access the <html/> element(which you should realize is the document element of this file),you can use the documentElement property of document:
var oHtml = document.documentElement;
The variable oHtml now contains an HTMLElement object representing <html/>.If you want to get the
<head/> and <body/>elements using oHtml, this works:
var oHead = oHtml.firstChild;
var oBody = oHtml.lastChild;
You can also use the childNodes property to accomplish the same thing.Just pretend that it’s a regular JavaScript Array and use square-bracket notation:
var oHead = oHtml.childNodes[0];
var oBody = oHtml.childNodes[1];
You can also get the number of child nodes by using the childNodes.length property:
alert(oHtml.childNodes.length);  //outputs “2”
Note that the square-bracket notation is a convenient implementation of the NodeList in JavaScript.The formal method of retrieving child nodes from the childNodes list is the item() method:
var oHead = oHtml.childNodes.item(0);
var oBody = oHtml.childNodes.item(1);
The HTML DOM also defines document.body as a pointer to the <body /> element:
var oBody = document.body;
With the three variables oHtml,oHead, and oBody,you can play around to determine their relationship to one another:
alert(oHead.parentNode == oHtml); //outputs “true”
alert(oBody.parentNode == oHtml); //outputs “true”
alert(oBody.previousSibling  == oHead); //outputs “true”
alert(oHead.nextSibling == oBody); //outputs “true”
alert(oHead.ownerDocument == document); //outputs “true”
This little snippet of code tests to make sure that the parentNode property of both oBody and oHead point to oHtml,as well as uses the previousSibling and nextSibling properties to establish their relationship to one another.The last line assures that the ownerDocument property of oHead actually does point back to the document.
Checking the node type
You can check the type of node by using the nodeType property:
alert(document.nodeType);  //outputs “9”
alert(document.documentElement.nodeType);  //outputs “1”
In this example,document.nodeType returns 9,which is equal to Node.DOCUMENT_NODE,and  document.documentElement.nodeType returns 1, which is equal to Node.ELEMENT_NODE.
You can also match up these values with the Node constants:
alert(document.nodeType == Node.DOCUMENT_NODE); //outputs “true”
alert(document.documentElement.nodeType == Node.ELEMENT_NODE); //outputs “true”
This code works in Mozilla 1.0+, Opera 7.0+, and Safari 1.0+. Unfortunately,Internet Explorer doesn’t support these constant values,so this code causes an error.You can remedy the situation by defining your own constants that match the node type constants,such as the following:
if(typeof Node == “undefined”) {
var Node = {
ELEMENT_NODE:  1,
ATTRIBUTE_NODE:  2,
TEXT_NODE:  3,
CDATA_SECTION_NODE:  4,
ENTITY_REFERENCE_NODE:  5,
ENTITY_NODE:  6,
PROCESSING_INSTRUCTION_NODE:  7,
COMMENT_NODE:  8,
DOCUMENT_NODE:  9,
DOCUMENT_TYPE_NODE:  10,
DOCUMENT_FRAGMENT_NODE:  11,
NOTATION_NODE:  12
}
}
The other option is to use the integer literals(although this may get confusing because not many people have memorized the node type values).
Dealing with attributes
As mentioned previously, only Element nodes have attributes even though the Node interface has an attributes method that is inherited by all node types. The attributes property for an Element node is a NamedNodeMap,which provides several methods for accessing and manipulating its contents:
  • getNamedItem(name) — returns the node whose nodeName property is equal to name
  • removeNamedItem(name) — removes the node whose nodeName property is equal to name from the list
  • setNamedItem(node) — adds the nodeinto the list,indexing it by its nodeName property
  • item(pos) — just like NodeList,returns the node in the numerical position pos
The NamedNodeMap object also has a length property to indicate the number of nodes it contains.
When used to represent attributes,each node in the NamedNodeMap is an Attr node, whose nodeName property is set to the attribute name. The nodeValue property is set to the attribute value. For example,suppose you had this element:
<p style=”color: red” id=”p1”>Hello world!</p>
Also, uppose that the variable oP that contains a reference to this element.You can access the value of the id attribute like this:
var sId = oP.attributes.getNamedItem(“id”).nodeValue;
Of course,you could access this id attribute numerically, which is a little less intuitive:
var sId = oP.attributes.item(1).nodeValue;
You can change the id attribute by setting a new value to the nodeValue property:
oP.attributes.getNamedItem(“id”).nodeValue = “newId”; Attr nodes also have a value property that is exactly equal (and kept in sync with) the nodeValue property, as well as a name property that is kept in sync with nodeName. You use any of these properties to modify or change the attributes.

Because this method is a little bit cumbersome, the DOM also defines three element methods to aid in the assignment of attributes:
  • getAttribute(name) — same as attributes.getNamedItem(name).value
  • setAttribute(name, newvalue) — same as attributes.getNamedItem(name).value = newvalue
  • removeAttribute(name) — same as attributes.removeNamedItem(name)
These methods are helpful in that they deal directly with the attribute values,completely hiding the Attr nodes.So, to retrieve the id attribute of the <p /> used earlier, you can just do this:
var sId = oP.getAttribute(“id”);
And to change the ID, you can do this:
oP.setAttribute(“id”, “newId”);
As you can see, these methods are much less verbose than using the NamedNodeMap methods.
Accessing specific nodes
You already know how to access parent and child nodes,but what if you want access to a node (or group of nodes) that are located deep in the document? Certainly,you don’t want to count child nodes until you get down to what you’re looking for. To help you in this use case, the DOM provides several methods to enable easy access to specific nodes.

getElementsByTagName()

The Core (XML) DOM defines the method getElementsByTagName()to return a NodeList of all Element objects whose tagName property is equal to a specific value.In an Element object, the tagName property is always equal to the name immediately following the less-than symbol — for example, the tagName of <img /> is “img”.The following line of code returns a list of all <img />
elements in a document:

var oImgs = document.getElementsByTagName(“img”);
After storing all of the images in oImgs, you can access them individually in the same way that you access child nodes, by using either square-bracket notation or the item() method (getElementsByTagName() returns a NodeList,just like childNodes):
alert(oImgs[0].tagName);  //outputs “IMG”
This line of code outputs the tagName of the first image, which is output as “IMG”. For some reason, most browsers still record the tag name as all uppercase even though XHTML conventions dictate that tag names must be all lowercase.
But suppose you want to get only the images within the first paragraph of a page.This can be accomplished by calling getElementsByTagName() on the first paragraph elementlike this:
var oPs = document.getElementsByTagname(“p”);
var oImgsInP = oPs[0].getElementsByTagName(“img”);
You can use this one method to get down to any element in the document or to get all elements in the document by using an asterisk:
var oAllElements = document.getElementsByTagName(“*”);
This line of code returns all the elements contained in document regardless of their tag names.
getElementsByName()
The HTML DOM defines getElementsByName() to retrieve all elements that have their name attributeset to a specific value. Consider the following HTML:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<form  method=”post” action=”dosomething.cgi”>
<fieldset>
<legend>What  color do you like?</legend>
<input type=”radio” name=”radColor” value=”red” /> Red<br />
<input type=”radio” name=”radColor” value=”green” /> Green<br />
<input type=”radio” name=”radColor” value=”blue” /> Blue<br />
</fieldset>
<input type=”submit” value=”Submit” />
</form>
</body>
</html>
This page asks the user which color he/she likes.The radio buttons all have the same name,because you only want to return one value for this field, which is the value attribute of the selected radio button. To get references to all the radio button elements, you can use the following code:
var oRadios = document.getElementsByName(“radColor”);
You can then manipulate the radio buttons the same way as you can any other element:
alert(oRadios[0].getAttribute(“value”));  //outputs “red”
getElementById()
The second method defined by the HTML DOM is getElementById(),which returns an element with its id attribute set to a specific value.In HTML, the id attribute is unique—meaning that no two elements can share the same id. This is undoubtedly the fastest method of retrieving a single specific element from the document tree. Suppose you have the following HTML page:
<html>
<head>
<title>DOM  Example</title>
</head>
<body>
<p>Hello  World!</p>
<div  id=”div1”>This is my first layer</div>
</body>
</html>
To access the <div /> element with the ID “div1”, you can use the getElementsByTagName() like this:
var oDivs = document.getElementsByTagName(“div”);
var oDiv1 = null;
for(var i=0; i < oDivs.length; i++){
if  (oDivs[i].getAttribute(“id”) == “div1”) {
oDiv1 = oDivs[i];
break;
}
}
Or,you could use getElementById() like this:
var oDiv1 = document.getElementById(“div1”);
As you can see, this is a much more streamlined way to get a reference to a specific element.
Creating and manipulating nodes
So far, you’ve learned how to access various nodes inside of a document, but that’s just the beginning of what can be done using the DOM. You can also add,remove,replace, and otherwise manipulate nodes within a DOM document. This functionality is what makes the DOM truly dynamic.
Creating new nodes
The DOM Document has a number of methods designed to create various types of nodes,even though the browser document object doesn’t necessarily support each of these methods in all browsers. The following table lists the methods included in DOM Level 1 and which browsers support each other.

The most commonly used methods are createDocumentFragment(),createElement(), and createTextNode(); the other methods are either not useful (createComment()) or not supported by enough browsers to be useful at this point in time.
createElement(),createTextNode(),appendChild()
Suppose you have the following HTML page:
<html>
<head>
<title>createElement()  Example</title>
</head>
<body>
</body>
</html>
To this page, you want to add the following code using the DOM:
<p>Hello  World!</p>
The createElement() and createTextNode() methods can be used to accomplish this. Here’s how.
The first thing to do is create the <p/> element:
var oP = document.createElement(“p”);
Second, create the text node:
var oText = document.createTextNode(“Hello World!”);
Next you need to add the text node to the element. To do this, you can use the appendChild() method,which was briefly mentioned earlier in the chapter. The appendChild() method exists on every node type and is used to add a given node to the end of another’s childNodes list. In this case, the text node should be added to the <p /> element:
oP.appendChild(oText);
You’re not done quite yet.You have created the element and text node and attached them to each other, but the element still doesn’t have a spot in the document.To actually be visible, the element must be attached either to the document.body element or one of its children. Once again, you can use the appendChild() method for this:
document.body.appendChild(oP);
To put all this into a sample you can run,just create a function containing each of these steps and call it when the page is loaded by using the onload event handler.
<html>
<head>
<title>createElement()  Example</title>
<script type=”text/javascript”>
function createMessage() {
var oP = document.createElement(“p”);
var oText = document.createTextNode(“Hello World! “);
oP.appendChild(oText);
document.body.appendChild(oP);
}
</script>
</head>
<body  onload=”createMessage()”>
</body>
</html>
When you run this code,the message “Hello World!” is displayed as if it were part of the HTML document all along.
removeChild(),replaceChild(), and insertBefore()
Naturally,if you can add a node you can also remove a node, which is where the removeChild() method comes in. This method accepts one argument,the node to remove,and then returns that node as the function value.So if, for instance, you start out with a page already containing the “Hello World!” message and you wanted to remove it, you can use the method like this:
<html>
<head>
<title>removeChild()  Example</title>
<script  type=”text/javascript”>
function  removeMessage() {
var  oP = document.body.getElementsByTagName(“p”)[0];
document.body.removeChild(oP);
}
</script>
</head>
<body  onload=”removeMessage()”>
<p>Hello  World!</p>
</body>
</html>
When this page is loaded,it displays a blank screen because the message is removed even before you have a chance to see it. Although this works, it’s always better to use a node’s parentNode property to make sure you are accessing its real parent:
<html>
<head>
<title>removeChild()  Example</title>
<script type=”text/javascript”>
function removeMessage() {
var  oP = document.body.getElementsByTagName(“p”)[0];
oP.parentNode.removeChild(oP);
}
</script>
</head>
<body  onload=”replaceMessage()”>
<p>Hello  World!</p>
</body>
</html>
But what if you want to replace this message with a new one? In that case, you can use the replaceChild() method. The replaceChild() method takes two arguments: the node to add and the node to replace. In this case, you create a new element with a new message and replace the <p /> element with the “Hello World!” message.
<html>
<head>
<title>replaceChild()  Example</title>
<script  type=”text/javascript”>
function  replaceMessage() {
var  oNewP = document.createElement(“p”);
var  oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
var  oOldP = document.body.getElementsByTagName(“p”)[0];
oOldP.parentNode.replaceChild(oNewP,  oOldP);
}
</script>
</head>
<body  onload=”replaceMessage()”>
<p>Hello  World!</p>
</body>
</html>
This sample page replaces the message “Hello World!” with “Hello Universe!” Note that this code still uses the parentNode property to ensure the correct parent is being manipulated. Of course,you may want both messages to appear.If you want the new message to come after the old message,use the appendChild() method:
<html>
<head>
<title>appendChild()  Example</title>
<script  type=”text/javascript”>
function  appendMessage() {
var  oNewP = document.createElement(“p”);
var  oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
document.body.appendChild(oNewP);
}
</script>
</head>
<body  onload=”appendMessage()”>
<p>Hello  World!</p>
</body>
</html>
If,however,you want the new message to come before the old, use the insertBefore() method.This method accepts two arguments: the new node to add and the node that it should be inserted before.In this example, the second argument is the <p /> element containing “Hello World!”:
<html>
<head>
<title>insertBefore()  Example</title>
<script  type=”text/javascript”>
function  insertMessage() {
var  oNewP = document.createElement(“p”);
var  oText = document.createTextNode(“Hello Universe! “);
oNewP.appendChild(oText);
var  oOldP = document.getElementsByTagName(“p”)[0];
document.body.insertBefore(oNewP,  oOldP);
}
</script>
</head>
<body  onload=”insertMessage()”>
<p>Hello  World!</p>
</body>
</html>
createDocumentFragment()
As soon as you add nodes to document.body (or one of its ancestors), the page is updated to reflect the changes. This is fine for a small number of changes, as in the previous examples.However, when a large amount of data has to be added to the document, it can be a very slow process if it adds changes one-byone.
To correct this situation, you can create a document fragment to which you attach all new nodes, and then add the contents of the document fragment to the document. Suppose you want to create ten new paragraphs.Using the methods you learned previously, you write this code:
var  arrText = [“first”, “second”, “third”, “fourth”, “fifth”, “sixth”, “seventh”,
“eighth”,  “ninth”, “tenth”];
for  (var i=0; i < arrText.length; i++) {
var  oP = document.createElement(“p”);
var  oText = document.createTextNode(arrText[i]);
oP.appendChild(oText);
document.body.appendChild(oP);}
This code works just fine, the problem is that it’s making ten calls to document.body.appendChild(),which causes a refresh of the page each time. This is where the document fragment is useful:
var  arrText = [“first”, “second”, “third”, “fourth”, “fifth”, “sixth”, “seventh”,
“eighth”,  “ninth”, “tenth”];
var oFragment = document.createDocumentFragment();
for(var i=0; i < arrText.length; i++) {
var oP = document.createElement(“p”);
var  oText = document.createTextNode(arrText[i]);
oP.appendChild(oText);
oFragment.appendChild(oP);
}
document.body.appendChild(oFragment);
In this code, each new <p /> element is added to the document fragment. Then,the fragment is passed in as the argument to appendChild().The call to appendChild() doesn’t actually append the document fragment node itself to the <body /> element; instead, it just appends the fragment’s child nodes. You can see the obvious performance gains: One call to document.body.appendChild() instead of 10 means only one screen refresh.

DOM HTML Features
The properties and methods of the Core DOM are generic,designed to work with every XML document in every situation.The properties and methods of the HTML DOM are specific to HTML and make certain DOM manipulations easier.These include the capability to access attributes as properties in addition to element-specific properties and methods that can make common tasks,such as building tables, much more straightforward.
Attributes as properties
For the most part,all attributes are included in HTML DOM elements as properties.For example,suppose you had the following image element:
<img src=”mypicture.jpg” border=”0” />
To get and set the src and border attributes using the Core DOM, you use the getAttribute() and setAttribute() methods:
alert(oImg.getAttribute(“src”));
alert(oImg.getAttribute(“border”));
oImg.setAttribute(“src”,  “mypicture2.jpg”);
oImg.setAttribute(“border”,  “1”);
However,using the HTML DOM,you can get and set these values using properties with the same name:
alert(oImg.src);
alert(oImg.border);
oImg.src = “mypicture2.jpg”;
oImg.border = “1”;
The only instance where the attribute name isn’t the same as the property name is in the class attribute,which specifies a CSS class to apply to an element,such as in the following:
<div class=”header”></div>
Because class is a reserved word in ECMAScript, it cannot be used as a variable, property, or function name in JavaScript.Therefore, the property is className:
alert(oDiv.className);

oDiv.className  = “footer”;
Using properties to modify attributes instead of getAttribute() and setAttribute() affords no real advantages aside from decreasing the code’s size and making it a little bit easier to read.
Table methods
Suppose you want to create the following HTML table using the DOM:
<table border=”1” width=”100%”> <tbody>
<tr>
<td>Cell  1,1</td>
<td>Cell  2,1</td>
</tr>
<tr>
<td>Cell  1,2</td>
<td>Cell  2,2</td>
</tr>
</tbody>
</table>
If you want to accomplish this with the Core DOM methods, your code would look something like this:
//create the table
var oTable = document.createElement(“table”);
oTable.setAttribute(“border”,  “1”);
oTable.setAttribute(“width”,  “100%”);
//create  the tbody
var  oTBody = document.createElement(“tbody”);
oTable.appendChild(oTBody);
//create  the first row
var  oTR1 = document.createElement(“tr”);
oTBody.appendChild(oTR1);
var  oTD11 = document.createElement(“td”);
oTD11.appendChild(document.createTextNode(“Cell  1,1”));
oTR1.appendChild(oTD11);
var  oTD21 = document.createElement(“td”);
oTD21.appendChild(document.createTextNode(“Cell  2,1”));
oTR1.appendChild(oTD21);
//create  the second row
var  oTR2 = document.createElement(“tr”);
oTBody.appendChild(oTR2);
var  oTD12 = document.createElement(“td”);
oTD12.appendChild(document.createTextNode(“Cell  1,2”));
oTR2.appendChild(oTD12);
var  oTD22 = document.createElement(“td”);
oTD22.appendChild(document.createTextNode(“Cell  2,2”));
oTR2.appendChild(oTD22);
//add  the table to the document body
document.body.appendChild(oTable);
This code is quite verbose and a little hard to follow. To facilitate building tables, the HTML DOM adds several properties and methods to the <table/>, <tbody/>,and <tr/> elements.
The <table/> element adds the following:
  • caption — pointer to the <caption/>element (if it exists)
  • tBodies — collection of <tbody/>elements
  • tFoot — pointer to the <tfoot/> element if it exists)
  • tHead — pointer to the <thead/> element(if it exists)
  • rows — collection of all rows in the table
  • createTHead() — creates a <thead/> element and places it into the table
  • createTFoot() — creates a <tfoot/> element and places it into the table
  • createCaption() — creates a <caption/> element and places it into the table
  • deleteTHead() — deletes the <thead/> element
  • deleteTFoot() — deletes the <tfoot/> element
  • deleteCaption() — deletes the <caption/> element
  • deleteRow(position) — deletes the row in the given position
  • insertRow(position) — inserts a row in the given position in the rows collection
The <tbody/> element adds the following:
  • rows — collection of rows in the <tbody/> element
  • deleteRow(position) — deletes the row in the given position
  • insertRow(position) — inserts a row in the given position in the rows collection
The <tr/> element adds the following:
  • cells — collection of cells in the <tr/> element
  • deleteCell(position) — deletes the cell in the given position
  • insertCell(position) — inserts a cell in the given position in the cells collection
What does all of this mean? Essentially, it means that creating a table can be a lot less complicated if you use these convenient properties and methods:
//create the table
var oTable = document.createElement(“table”);
oTable.setAttribute(“border”,  “1”);
oTable.setAttribute(“width”,  “100%”);
//create  the tbody
var  oTBody = document.createElement(“tbody”);
oTable.appendChild(oTBody);
//create  the first row
oTBody.insertRow(0);
oTBody.rows[0].insertCell(0);
oTBody.rows[0].cells[0].appendChild(document.createTextNode(“Cell  1,1”));
oTBody.rows[0].insertCell(1);
oTBody.rows[0].cells[1].appendChild(document.createTextNode(“Cell  2,1”));
//create  the second row
oTBody.insertRow(1);
oTBody.rows[1].insertCell(0);
oTBody.rows[1].cells[0].appendChild(document.createTextNode(“Cell  1,2”));
oTBody.rows[1].insertCell(1);
oTBody.rows[1].cells[1].appendChild(document.createTextNode(“Cell  2,2”));
//add  the table to the document body
document.body.appendChild(oTable);
In this code, the creation of the <table/> and <tbody/> elements remain the same.What has changed is the section creating the two rows, which now makes use of the HTML DOM Table properties and methods. To create the first row, the insertRow() method is called on the <tbody/> element with an argument of 0, which indicates the position in which the row should be placed. After that point,the row can be referenced by oTBody.rows[0] because it is automatically created and added into the <tbody/> element in position 0.
Creating a cell is done in a similar way — calling insertCell() on the <tr/> element and passing in the position in which the cell should be placed. The cell can then be referenced by oTBody.rows[0].cells[0] because the cell has been created and inserted into the row in position 0.
Using these properties and methods to create a table makes the code much more logical and readable, although technically both sets of code are correct.

DOM Traversal
Up until this point,the features discussed have all been part of DOM Level 1.This section introduces some of the features of DOM Level 2,specifically objects in the DOM Level 2 Traversal and Range specification relating to traversing a DOM document.These features are only available in Mozilla and Konqueror/Safari.
NodeIterator
The first object of interest is the NodeIterator, which enables you to do a depth-first search of a DOM tree,which can be useful if you are looking for specific types of information(or elements) in a page. To understand what the NodeIterator does,consider the following HTML page:
<html>
<head>
<title>Example</title>
</head>
<body>
<p>Hello  <b>World!</b></p>
</body>
</html>
This page evaluates to the DOM tree represented .

When using a NodeIterator, it’s possible to start from the document element, <html/>,and traverse the entire DOM tree in a systematic way known as a depth-first search.In this method of searching, the traversal goes as deep as it possibly can from parent to child,to that child’s child, and so on, until it can’t go any further. Then, the traversal goes back up one level and goes to the next child. For instance,in the DOM tree shown previously, the traversal first visits <html/>,then <head/>, then <title/>,then the text node “Example”, before going back up to <body/>.displays the complete path for the traversal.
The best way to think of a depth-first search is to draw a line that starts from the left of the first node and follows the outline of the tree. Whenever the line passes a node on its left,the node appears next in the search (this line is indicated by the thick line in )

To create a NodeIterator object,use the createNodeIterator() method of the document object.Thismethod accepts four arguments:
  1. root — the node in the tree that you wish to start searching from
  2. whatToShow — a numerical code indicating which nodes should be visited
  3. filter — a NodeFilter object to determine which nodes to ignore
  4. entityReferenceExpansion — a Boolean value indicating whether entity references should be expanded
The whatToShow argument determines which nodes to visit by applying one or more of the following constants:
  • NodeFilter.SHOW_ALL — show all node types
  • NodeFilter.SHOW_ELEMENT — show element nodes
  • NodeFilter.SHOW_ATTRIBUTE — show attribute nodes
  • NodeFilter.SHOW_TEXT — show text nodes
  • NodeFilter.SHOW_CDATA_SECTION — show CData section nodes
  • NodeFilter.SHOW_ENTITY_REFERENCE — show entity reference nodes
  • NodeFilter.SHOW_ENTITY — show entity nodes
  • NodeFilter.SHOW_PROCESSING_INSTRUCTION — show PI nodes
  • NodeFilter.SHOW_COMMENT — show comment nodes
  • NodeFilter.SHOW_DOCUMENT — show document nodes
  • NodeFilter.SHOW_DOCUMENT_TYPE — show document type nodes
  • NodeFilter.SHOW_DOCUMENT_FRAGMENT — show document fragment nodes
  • NodeFilter.SHOW_NOTATION — show notation nodes
You can combine multiple values by using the bitwise OR operator:
var iWhatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
The filter argument of createNodeIterator() can be used to specify a custom NodeFilter object, but can also be left null if you don’t want to use it.
To create a simple NodeIterator that visits all node types, use the following:
var iterator = document.createNodeIterator
(document, NodeFilter.SHOW_ALL, null, false);
To move forward and backward in the search,use the nextNode() and previousNode() methods:
var  node1 = iterator.nextNode();
var  node2 = iterator.nextNode();
var  node3 = iterator.previousNode();
alert(node1  == node3); ///outputs “true”
For example, suppose you wanted to list all elements contained within a specific <div/> inside of a area on an HTML page.The following code accomplishes this:
<html>
<head>
<title>NodeIterator  Example</title>
<script  type=”text/javascript”>
var  iterator = null;
function  makeList() {
var  oDiv = document.getElementById(“div1”);
iterator  = document.createNodeIterator(oDiv,
NodeFilter.SHOW_ELEMENT,  null, false);
var  oOutput = document.getElementById(“text1”);
var  oNode = iterator.nextNode();
while  (oNode) {
oOutput.value  += oNode.tagName + “n”;
oNode  = iterator.nextNode();
}
}
</script>
</head>
<body>
<div  id=”div1”>
<p>Hello  <b>World!</b></p>
<ul>
<li>List  item 1</li>
<li>List  item 2</li>
<li>List  item 3</li>
</ul>
</div>
<textarea  rows=”10” cols=”40” id=”text1”></textarea><br />
<input type=”button” value=”Make List” onclick=”makeList()” /> </body>
</html>
When the button is clicked, the <textarea/> is filled with the tag names of the elements contained in
div1:
P
B
UL
LI
LI
LI
But suppose you don’t want to include <p/>elements in the results. This can’t be accomplished just by using the whatToShow argument.In this case, you need a custom NodeFilter object. ANodeFilter object has only one method:
acceptNode(),which returns NodeFilter.FILTER_ACCEPT if the given node should be visited or NodeFilter.FILTER_REJECT if the given node should not be visited.
However,you cannot create an object using the class NodeFilter because it is an abstract class. In Java or other languages, you must define a new subclass of NodeFilter, but because this is JavaScript you can’t do that.
Instead,you just create an object with an acceptNode() method and pass that to the createNodeIterator() method,like this:
var  oFilter = new Object;
oFilter.acceptNode  = function (oNode) {
//filter  logic goes here
};
To disallow <p/> element nodes, you just check the tagName property and return NodeFilter.
FILTER_REJECT if it’s equal to “P”:
var  oFilter = new Object;
oFilter.acceptNode  = function (oNode) {
return  (oNode.tagName == “P”) ? NodeFilter.FILTER_REJECT :
NodeFilter.FILTER_ACCEPT;
};
If you include this in the previous example,the code becomes the following:

<html>
<head>
<title>NodeIterator Example</title>
<script type=”text/javascript”>
var iterator = null;
function  makeList() {
var oDiv = document.getElementById(“div1”);
var oFilter = new Object;
oFilter.acceptNode = function (oNode) {
return (oNode.tagName == “P”) ?
NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
};
iterator = document.createNodeIterator(oDiv,
NodeFilter.SHOW_ELEMENT, oFilter, false);
var oOutput = document.getElementById(“text1”);
var oNode = iterator.nextNode();
while(oNode) {
oOutput.value  += oNode.tagName + “n”;
oNode  = iterator.nextNode();
}
}
</script>
</head>
<body>
<div  id=”div1”>
<p>Hello  <b>World!</b></p>
<ul>
<li>List  item 1</li>
<li>List  item 2</li>
<li>List  item 3</li>
</ul>
</div>
<textarea  rows=”10” cols=”40” id=”text1”></textarea><br />
<input  type=”button” value=”Make List” onclick=”makeList()” /> </body>
</html>
This time when the button is clicked, the <textarea/> is filled with the following:
UL
LI
LI
LI

Note that both “P” and “B” have disappeared from the list. This is because filtering out the <p/> element eliminates it and all its ancestors from the iteration search.Because <b/> is a child of <p/>,it is also skipped.
The NodeIterator object presents an orderly way of traversing an entire DOM tree(or just part of it) from top to bottom. However, you may want to traverse a particular area of the tree and then look at a node’s sibling or child. In that case, you use a TreeWalker.
TreeWalker
The TreeWalker is like the big brother of NodeIterator: It has all the same functionality (with nextNode() and previousNode()) but with added traversal methods:
  • parentNode()— travels to the current node’s parent
  • firstChild()— travels to the first child of the current node
  • lastChild()— travels to the last child of the current node
  • nextSibling()— travels to the next sibling of the current node
  • previousSibling()— travels to the previous sibling of the current node
To start, you can actually use a TreeWalker just like a NodeIterator by replacing the call to createNodeIterator() with a call to createTreeWalker(), which accepts the same arguments:
<html>
<head>
<title>TreeWalker  Example</title>
<script  type=”text/javascript”>
var  walker = null;
function  makeList() {
var  oDiv = document.getElementById(“div1”);
var  oFilter = new Object;
oFilter.acceptNode  = function (oNode) {
return  (oNode.tagName == “P”) ?
NodeFilter.FILTER_REJECT  : NodeFilter.FILTER_ACCEPT;
};
walker  = document.createTreeWalker(oDiv, NodeFilter.SHOW_ELEMENT,
oFilter,  false);
var  oOutput = document.getElementById(“text1”);
var  oNode = walker.nextNode();
while  (oNode) {
oOutput.value  += oNode.tagName + “n”;
oNode  = walker.nextNode();
}
}
</script>
</head>
<body>
<div  id=”div1”>
<p>Hello  <b>World!</b></p>
<ul>
<li>List  item 1</li>
<li>List  item 2</li>
<li>List  item 3</li>
</ul>
</div>
<textarea  rows=”10” cols=”40” id=”text1”></textarea><br />
<input  type=”button” value=”Make List” onclick=”makeList()” /> </body>
</html>
Naturally,the true power of a TreeWalker is lost on a simple example such as this;it is much more useful in cases when you don’t want to go straight through the entire DOM tree. For example, suppose you only want to visit the <li/>elements in the HTML page shown previously. You could write a filter that only accepts elements with the tagName “LI”, or you could use a TreeWalker to do a purposive traversal:
<html>
<head>
<title>TreeWalker  Example</title>
<script type=”text/javascript”>
var walker = null;
function  makeList() {
var oDiv = document.getElementById(“div1”);
walker = document.createTreeWalker(oDiv, NodeFilter.SHOW_ELEMENT,
null, false);
var oOutput = document.getElementById(“text1”);
walker.firstChild();  //go to <p>
walker.nextSibling();  //go to <ul>
var oNode = walker.firstChild(); //go to first <li>
while (oNode) {
oOutput.value  += oNode.tagName + “n”;
oNode  = walker.nextSibling();
}
}
</script>
</head>
<body>
<div  id=”div1”>
<p>Hello  <b>World!</b></p>
<ul>
<li>List  item 1</li>
<li>List  item 2</li>
<li>List  item 3</li>
</ul>
</div>
<textarea  rows=”10” cols=”40” id=”text1”></textarea><br />
<input  type=”button” value=”Make List” onclick=”makeList()” />
</body>
</html>
In this example, the TreeWalker is created and immediately firstChild() is called, which points thenwalker at the <p/> element (because <p/> is the first child of div1). When nextSibling() is called on the next line, the walker goes to <ul/>, which is the next sibling of <p/>. Then, firstChild() is called to return the first <li/> element under <ul/>.After it is inside the loop, the nextSibling() method is used to iterate through the rest of the <li/> elements. When you click the button, the output is the following:
LI
LI
LI
The bottom line is that the TreeWalker is much more useful when you have an idea about the structure of the DOM tree you will be traversing, whereas a NodeIterator is much more practical when you don’t know the structure.

Detecting DOM Conformance
As you can tell,there’s a lot to the DOM.For this reason,you have a method to determine which part of the DOM are supported by any given implementation. The object is named, ironically enough,implementation.
The implementation object is a property of a DOM Document,and is,therefore, part of the browser document object. The sole method of implementation is hasFeature(),which accepts two parameters: the feature to check and the version of that feature. For instance,if you want to check for support of XML DOM Level 1,the call would be:
var bXmlLevel1 = document.implementation.hasFeature(“XML”, “1.0”);
The following table lists all the DOM feature and the corresponding versions to check for:

Although it is a nice convenience,the drawback of using implementation.hasFeature() is that the implementor gets to decide if the implementation is indeed conformant with the various parts of the DOM specification.It’s very easy to make this method return true for any and all values, but that doesn’t necessarily mean that the implementation conforms to all the specifications it claims to.At present time,the most accurate browser is Mozilla, which more or less actually does conform to the DOM specs that return true for this method.

DOM Level 3 DOM Level 3 was introduced as a W3C Recommendation in April of 2004.To date,no browser has fully implemented it,although Mozilla has implemented parts.It is unknown at what rate Web browsers will begin adding their missing DOM features because Internet Explorer hasn’t had an update in nearly four years (meaning no changes to its level of DOM support).Mozilla has pledged to remain as compliant as possible moving forward and continues to be the leader in DOM support. However,Opera rewrote its core browser components to better support the DOM standards and has a newfound zest for keeping up-to-date with the latest technology. Even Apple’s Safari browser,which is based on Konqueror,is moving forward with plans to implement as much DOM functionality as possible.
No further development is planned on the DOM after Level 3 rounded out all the missing functionality.Therefore,browsers now have a finite finish line to reach in order to achieve DOM compliance.One can only hope that they all reach it someday.
Post a Comment