标题：DOM Tree
概要
DOM技术被Internet Explorer 5.0及以上版本的浏览器所支持，它采取一种非常直观且一致的方式将HTML文档进行模型化处理，并借此提供访问、导航和操作页面的简易编程接口。通过DOM技术，我们不仅能够访问和更新页面的内容及结构，而且还能操纵文档的风格样式。DOM由W3C组织所倡导，这样，大多数浏览器都将最终支持这项技术。
DOM和DHTML对象模型的比较
可以这么说，DOM是从DHTML对象模型发展而来的。但更准确而言，DOM对象是对DHTML对象模型进行了根本变革的产物。
借助DHTML对象模型技术，我们能够单独地访问并更新HTML页面上的对象，每个HTML标记通过它的ID和NAME属性被操纵，每个对象都具有自己的属性、方法和事件，通过方法操纵对象，通过事件触发因果过程。
DOM则要比DTHML对象模型功能更全面，它提供了一个对整个文档的访问模型，而不仅仅再局限于单一的HTML标记（Tag）范围内。DOM将文档描绘为一个树形（Tree）结构，Tree的每个节点表现为一个HTML标记或者HTML标记内的文本项。树形结构精确地描述了HTML文档中标记间以及文本项间的相互关联性，这种关联性包括child（孩子）类型、parent（双亲）类型和兄弟（sibling）类型。
使用DHTML对象模型访问和更新HTML页面内容时，不可避免地需要查询相关技术手册。因为HTML对象很多，每个HTML对象又有很多的属性、方法和事件。但是采用DOM技术访问和更新HTML页面内容时，任何手册都可以放在一边了。首先查看一下HTML源代码，推算出页面的Tree结构模型；然后，按照层次结构关系操纵需要的属性。比如要更新页面上的文本项内容，如果采用DTHML对象模型，需要使用到innerHTML属性，但必须要注意并不是所有的HTML对象都支持innerHTML属性；如果采用DOM技术，只要修改相关Tree节点都具有的nodeValue属性值即可。
DOM技术使我们可以方便地沿着文档的树型结构在上、下以及一侧方向做节点导航，从页面的任何地方开始，使用child、parent或者sibling三种关联性组成的表达式代表页面的另外地方。而DTHML对象模型不包含Tree结构，所以也就不具备页面对象的相互导航功能。当我们从一个标记对象开始时，不可能用关联表达式来表达相近的标记。虽然对于某些标记，比如 <TABLE> ，DHTML对象模型可以提供特殊的属性和方法存取相关内容，但实现方式和效果远不如DOM技术显得一致化和直观化。采用DTHML对象模型访问<TABLE> 中的单元（cell）内容时，首先要查询手册确定单元的坐标值i、j，然后再通过表达式tableObj.rows[i].cells[j].innerHTML实现访问。但对于DOM来说，访问TABLE每个单元的内容将变得非常简单，只需要建立一个节点导航表达式就可以。
另外，DOM技术允许我们操纵文档的Tree结构，这包括创建新节点（nodes）、删除存在的节点以及在Tree中移动节点。实际上，这就是执行创建新标记（tags）、删除存在的标记以及在文档中移动标记的过程。DTHML对象模型则不允许更改文档结构，我们只能操纵现有的对象。
DOM提供了一套属性用于导航、访问和更新文档内容，其中包括只读类型的属性和可读写类型的属性。
下表是只读类型的属性：DOM对象属性 返 回 值FirstChild 返回一个对象（Object），表示第一个孩子节点（child node）。 
LastChild 返回一个对象（Object），表示最后一个孩子节点（child node）。 
NextSibling 返回一个对象（Object），表示下一个相邻的兄弟节点。 
NodeName 返回节点对应的HTML标记。比如：P，Script。对应文本项节点，返回#text。 
nodeType 返回节点的类型，
1表示此节点是标记（tag），
2表示属性（attribute），
3表示文本项。 
parentNode 返回一个对象（Object），表示当前节点的双亲节点（parent node）。 
previousSibling 返回一个对象（Object），表示前一个相邻的兄弟节点。 
specified 返回一个布尔型变量（Boolean），表示是否设置了属性值（attribute）。 
下表是可读写类型的属性：DOM对象属性 返 回 值data 返回一个字符串，表示文本项节点的值。如果是其他类型节点，返回undefined。 
nodeValue 返回一个字符串，表示文本项节点的值。如果是其他类型节点，返回null。 
下表是DOM中相关属性集合：DOM对象属性 返 回 值attributes 表示节点的属性集合，通过id来访问，比如attributes. id。 
childNodes 表示节点的孩子节点集合，通过数组索引方式访问，比如：childNodes[2]。 与DHTML对象模型相比较，DOM只有一个缺憾：DOM不能支持事件处理，而DTHML对象模型对于文档对象则拥有一个广泛的事件处理功能。
DOM Tree中三种重要的节点：
Element Node : .com"></a> 中href="http:_//ww_w.test.c_om"即是这个a的属性节点
Text Node : nodeType=3
文本节点 如<span>text</span>中的“text”即是一个文本节点
注意：通过obj.nodeType得到的值就可以判断访问到的是哪种节点。
得到指定的元素节点oNode：
document.getElementById(sid)
document.getElementsByName(sname)
document.getElementsByTagName(stagname)
注意：
document是所有节点的父节点。
元素节点的ID要保持唯一不变。
节点name属性可以重复，但是在IE下getElementsByName对于DIV节点无效，所以不推荐使用。
从一个节点oNode出发访问相关元素或者文本节点：
oNode.firstChild();
oNode.lastChild();
oNode.previousSibling();
oNode.nextSibling();
oNode.childNodes();
oNode.parentNode();
注意：<div>x<a>y</a>z</div>这个HTML片段.，在FireFox下如果x处为空，也会被认为存在一个空的文本节点，所以在进行DomTree遍历时要根据nodeType判断，来确保找到想找的节点
访问节点oNode的属性节点
oNode.getAttribute(sName);
oNode.setAttribute(sName,sValue);
Javascrīpt控制展现的三种方式
1、   使用document.write(sHTML) document.writeln(sHTML)
这个相当于PHP的echo()
参数sHTML将被输出在该语句执行时的位置成为HTML的一部分。
注意：这个方法只可以在文档载入过程中使用。
2、   使用oNode.innerHTML = sHTML
改变oNode节点内部的innerHTML
注意：
IE下无法改变,<table><tbody><thead><tfoot><tr>这些节点的innerHTML，只能改变<td>的innerHTML
innerHTML非DOM标准的方法，但是FireFox IE等所有浏览器都支持，但innerText,outerHTML,outerText就只有IE才支持，所以不要使用。
3、重头戏，使用Dom方法
创建、复制元素或文本节点：
var newNode = document.createElement(sTag)
var newNode = document.createTextNode([sText])
var newNode = oNode.cloneNode(true)           true：复制包含子节点 false：不包含子节点
插入、替换元素或文本节点：
oNode.appendChild(newNode);
oNode.insertBefore(newNode,childNode);
oNode.replaceChild(newNode, childNode)
删除元素或文本节点
oNode.removeChild(childNode)
注意：
使用第2、3种方法时，操作涉及的已有oNode必须已经完整载入后才可以，比如
<div id="t"><scrīpt>document.getElementById("t")</scrīpt></div>在div元素没有闭合时就访问这个div是要严格禁止的。
使用第3种方法创建<table>时不能把<tr>直接作为<table>的子节点，必须加一层<tbody> <thead>或者<tfoot>，否则显示不出来
针对属性节点，增加和修改都使用oNode.setAttribute()方法即可，删除没什么意义
DOM Tree实例
下面让我们来对一个简单的文档进行分析，最终形成它的DOM结构。要分析的文档包括3个段落，HTML代码如下：
<HTML>
<HEAD>
<TITLE> Simple DOM Demo </TITLE>
</HEAD>
<BODY ID="bodyNode"><P ID = "p1Node">This is paragraph 1.</P>
This is the document body
<P ID = "p2Node"> </P>
<P ID = "p3Node"></P>
</BODY>
</HTML> 
请注意，从现在开始，我们就要按照Tree结构以及家族关系的方式来看待整个文档了。 <BODY>标记是Tree的根节点，它包含了4个孩子节点：p1Node、文本项节点（“This is the document body”）、p2Node和p3Node。每个孩子节点或者是一个HTML标记型节点，或者是一个文本项型节点。在一对开始标记和结束标记间的内容属于这个标记的孩子节点，比如“This is paragraph1”就是p1Node节点的孩子节点，同时它本身也是一个文本项型节点。文本项型节点必须包含一个非空字符，因此，第2段和第3段的孩子节点是不存在的。
这里有上述HTML文档的DOM Tree图示，它能帮助我们更好地理解节点间的相互关系： 
HTML中有一些标记不包含关闭括弧，这种情况下，我们可以将下一个紧挨者的标记作为关闭括弧对待。比如<LI>标记可以将紧挨者的<LI>或<UL>标记作为关闭标识。
简单文档的节点导航
文档的DOM Tree结构为每个标记和文本项设置了一个节点，对于任一被分配了ID属性的节点，都可以作为起始点开始整个Tree的“攀登”。而且，借助DOM属性的强大功能，我们可以寻址到Tree中的每一个节点。
在继续讲述前，请再次看看上一节中的简单文档的HTML源代码以及它的DOM Tree结构图。我们可以得知：图中的箭头表示了可以到达Tree中其他节点的导航路线；<BODY>标记的ID属性值是bodyNode，3个<P>标记的ID属性值依次为p1Node、p2Node和p3Node。下面，我们分别从不同的节点开始，举例说明如何寻址到其他的节点： 
起始节点 到达节点 寻址表达式 
<BODY> p1Node bodyNode.firstChild 或bodyNode.childNodes[0] 
p1Node的孩子节点 bodyNode.firstChild.firstChild 
文本项节点 bodyNode.childNodes[1] 
p3Node BodyNode.childNodes[3] 或bodyNode.lastChild 
p1Node 文本项节点 p1Node.nextSibling 
p2Node p1Node.nextSibling.nextSibling 
p3Node p1Node.nextSibling.nextSibling.nextSibling 
p3Node p1Node的孩子节点 p3Node.previousSibling.previousSibling.previousSibling.childNodes[0] 
以上列举的都是从双亲（parent）到孩子或者孩子到孩子方向的寻址表达式，借助我们介绍另外一种导航方向：使用parentNode属性从孩子到双亲。比如：要从每一个<P>标记开始寻址到<BODY>标记，可以使用p1Node.parentNode、p2Node.parentNode或者 p3Node.parentNode。
为了加深对以上节点导航表达式的理解，我们编写了一段JavaScript代码，它将显示出文档DOM的每个节点的nodeName值。请注意，除了上面举例的简单文档中涉及到的节点外，还包含一个<Script>标记节点。为了不使问题复杂化，代码中不使用lastChild属性。代码如下：
<HTML>
<HEAD>
<TITLE> Simple DOM Demo </title>
<STYLE>TYPE="text/css">
<!--
FORM.tb {display:inline;}
.twidth{width:100%}
.include{ font-size: 75%; font-family: verdana, arial, helvetica;}
.includebig{font-family: verdana, arial, helvetica;}
.includebig A:link { color: blue; }
.includebig A:visited { color: purple; }
.include A:link { color: blue; }
.include A:visited { color: purple; }
.submitter { font-size: 75%; font-family: verdana, arial, helvetica; }
pre.code {color: #660099; margin-left:5%}
address {text-align: right}
body {background:#FFFFFF; margin-left: 5%; margin-right: 5%}
-->
</STYLE>
</HEAD>
<BODY ID="bodyNode"><P ID = "p1Node">This is paragraph 1.</P>
This is the document body
<P ID = "p2Node"> </P>
<P ID = "p3Node"></P>
<SCRIPT LANGUAGE="JavaScript">
alert(
"bodyNode.firstChild.nodeName = " + bodyNode.firstChild.nodeName + "\n" +
"bodyNode.firstChild.data = " + bodyNode.firstChild.data + "\n" +
"bodyNode.childNodes[0].nodeName = " + bodyNode.childNodes[0].nodeName + "\n" +
"bodyNode.childNodes[1].nodeName = " + bodyNode.childNodes[1].nodeName + "\n" + 
"bodyNode.childNodes[1].data = " + bodyNode.childNodes[1].data + "\n" + 
"bodyNode.childNodes[3].nodeName = " + bodyNode.childNodes[3].nodeName + "\n" +
"bodyNode.childNodes[4].nodeName = " + bodyNode.childNodes[4].nodeName + "\n" +
"p1Node.nextSibling.nodeName = " + p1Node.nextSibling.nodeName + "\n" +
"p1Node.nextSibling.nextSibling.nodeName = " + p1Node.nextSibling.nextSibling.nodeName + "\n" +
"p1Node.nextSibling.nextSibling.nextSibling.nodeName = " + p1Node.nextSibling.nextSibling.nextSibling.nodeName+ "\n" +
"p3Node.previousSibling.previousSibling.previousSibling.childNodes[0].nodeName = " + 
p3Node.previousSibling.previousSibling.previousSibling.childNodes[0].nodeName + "\n" +
"p1Node.parentNode.nodeName = " + p1Node.parentNode.nodeName + "\n" + 
"p2Node.parentNode.nodeName = " + p2Node.parentNode.nodeName + "\n" +
"p3Node.parentNode.nodeName = " + p3Node.parentNode.nodeName + "\n" + 
"bodyNode.firstChild.firstChild.parentNode.parentNode.nodeName = " +
bodyNode.firstChild.firstChild.parentNode.parentNode.nodeName + "\n"
);
</SCRIPT>
</BODY>
</HTML>