DOM (Document Object Model)是一套语言无关的XML解析的接口定义。它定义了在XML解析中需要的类型,方法,以及属性,比如如何获得一个XML标签,如何改变标签的内容,如何改变它的属性,等等。
DOM只是一个定义,并不是具体的实现,它的目的就是为了让大家在各个平台上都能用相同的方式来处理XML,这样一来,我只要了解DOM,基本上在各个平台上都可以方便的处理XML,而不用重新学习了。比如说,Java, JavaScript, Python都有DOM的实现,用它们来处理XML,方式基本上都是一样的(当然也有非DOM的XML解析方式)。在Java下,实现DOM的类库就有很多,比如JDom,Xerces, 用GOOGLE一搜就一大把。现在Java 5.0内置的就是Xerces。而JavaScript本身就内置了DOM的实现。Python也默认安装了DOM的库。
正因为DOM致力于实现各个平台上对XML一致的处理方式,它定义了一堆自己的接口。因此在用DOM的时候,会有很多非NATIVE的东东。比如说,返回节点的子节点的方法,childNodes,返回的类型是NodeList。我第一次在Java上用,就以为是返回一个List,然后用get(n)方法来取得某元素。而实际上NodeList是用item(n)的方法来取得某元素的。这就让我觉得很怪。而DOM正是用这种方式来获得“语言无关”的能力的。
DOM是用IDL(Interface Definition Language)来定义的。完整的定义可以在这里找到 http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html。IDL也很容易看懂。定义的1.1节列出了所有的接口。
这些接口里,最重要而且常用的是Node,NodeList,Document,Element,Text,Attr这几个。DOM把XML文档看作一棵树,树上的每个元素都是Node。每个Node都属于某个类型,比如Element,attribute,text等。这些类型就表明这个节点在XML文档里的类型了。
比如Node里有个属性:
readonly attribute unsigned
short
nodeType;
根据这个定义,对于取得的节点,我们就可以通过读取nodeType这个属性来判断这个节点的类型。在Java里,所有的属性都是用getter来取得的,因此对某节点n,就可以用n.getNodeType()取得它的类型。Node接口里也定义了类型常量:
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2;
const unsigned short TEXT_NODE = 3;
const unsigned short CDATA_SECTION_NODE = 4;
const unsigned short ENTITY_REFERENCE_NODE = 5;
const unsigned short ENTITY_NODE = 6;
const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
const unsigned short COMMENT_NODE = 8;
const unsigned short DOCUMENT_NODE = 9;
const unsigned short DOCUMENT_TYPE_NODE = 10;
const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
const unsigned short NOTATION_NODE = 12;
用这些常量和和n.getNodeType()的结果比较,就可以知道它是不是某种类型。
Node接口中也定义了一些方法,比如:
Node appendChild(in Node newChild) raises(DOMException);
表明appendChild方法需要一个Node类型的参数,返回一个Node。 具体的说明可以点文档上的链接进去,也很容易看懂。
Node接口里定义了操纵节点的方法,比如增加子节点,返回父节点,插入新节点,返回节点类型,等等。Document,Element等接口都继承Node接口,因此在它们上面都可以使用操纵节点的方法。
Document:代表整个XML文档。所有DOM元素都不能用类似Java里new的方式来生成,而是要通过调用Document里的相应方法来生成。因此它提供了生成诸如Element, Attr, Text的方法。比如createElement, createTextNode, createComment等。它也提供了名为getElementsByTagName的方法,用来通过标签名称来取得其对象。比如getElementByTagName("ul")就可以获得所有ul标签。它也提供一些文档的属性,比如xmlEncoding,inputEncoding等。它的一个属性,documentElement代表文档的根节点。所有对XML元素的操作,基本上都是从Document开始的。
Element:代表一个XML标签。它可以有属性,子标签,等。比如<ul id="booklist"><li>hello</li></ul>。标签ul是一个Element,它有一个属性叫id,属性的值是booklist。它有一个子结点li。li也是一个标签,它也有个子节点hello,是一个Text类型的节点。这个接口提供操纵其标签属性的方法,比如getAttribute,setAttribute,removeAttribute等。它也提供了和Document中一样的getElementsByTagName的方法,用来获得在这个节点下的元素。
Attr:代表标签中的属性。比如上面的id。它也是一个Node。它有名字,值,也可以获得它的所属标签。
Text:代表一段文字,比如上面的hello,它也一个Node,但比较特殊,它不是直接继承Node,而是继承CharacterData接口,后者继承了Node。但是它不能有子节点。
用JavaScript给一个例子。假设有一个HTML文档:
<
html
><
head
><
title
>
Try DOM
</
title
></
head
><
body
>
<
ul
>
<
li
>
hello
</
li
>
<
li
>
world
</
li
>
</
ul
>
</
body
></
html
>
下面是增加一个li的JavaScript方法:
ulList
=
document.getElementsByTagName(
"
ul
"
);
ul
=
ulList.item(
0
);
txt
=
document.createTextNode(
"
I am new li
"
);
li
=
document.createElement(
"
li
"
);
li.appendChild(txt);
ul.appendChild(li);
用Java来写,是这样:
NodeList ulList
=
document.getElementsByTagName(
"
ul
"
);
Node ul
=
ulList.item(
0
);
Text txt
=
document.createTextNode(
"
I am new li
"
);
Element li
=
document.createElement(
"
li
"
);
li.appendChild(txt);
ul.appendChild(li);
可以看到处理方式和数据类型都是一样的。如果要了解更多,可以看看DOM的定义,都是IDL。