DOM (Document Object Model)是一套語言無關(guān)的XML解析的接口定義。它定義了在XML解析中需要的類型,方法,以及屬性,比如如何獲得一個XML標(biāo)簽,如何改變標(biāo)簽的內(nèi)容,如何改變它的屬性,等等。
DOM只是一個定義,并不是具體的實現(xiàn),它的目的就是為了讓大家在各個平臺上都能用相同的方式來處理XML,這樣一來,我只要了解DOM,基本上在各個平臺上都可以方便的處理XML,而不用重新學(xué)習(xí)了。比如說,Java, JavaScript, Python都有DOM的實現(xiàn),用它們來處理XML,方式基本上都是一樣的(當(dāng)然也有非DOM的XML解析方式)。在Java下,實現(xiàn)DOM的類庫就有很多,比如JDom,Xerces, 用GOOGLE一搜就一大把。現(xiàn)在Java 5.0內(nèi)置的就是Xerces。而JavaScript本身就內(nèi)置了DOM的實現(xiàn)。Python也默認安裝了DOM的庫。
正因為DOM致力于實現(xiàn)各個平臺上對XML一致的處理方式,它定義了一堆自己的接口。因此在用DOM的時候,會有很多非NATIVE的東東。比如說,返回節(jié)點的子節(jié)點的方法,childNodes,返回的類型是NodeList。我第一次在Java上用,就以為是返回一個List,然后用get(n)方法來取得某元素。而實際上NodeList是用item(n)的方法來取得某元素的。這就讓我覺得很怪。而DOM正是用這種方式來獲得“語言無關(guān)”的能力的。
DOM是用IDL(Interface Definition Language)來定義的。完整的定義可以在這里找到 http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html。IDL也很容易看懂。定義的1.1節(jié)列出了所有的接口。
這些接口里,最重要而且常用的是Node,NodeList,Document,Element,Text,Attr這幾個。DOM把XML文檔看作一棵樹,樹上的每個元素都是Node。每個Node都屬于某個類型,比如Element,attribute,text等。這些類型就表明這個節(jié)點在XML文檔里的類型了。
比如Node里有個屬性:
??readonly?attribute?unsigned?
short
??nodeType;
根據(jù)這個定義,對于取得的節(jié)點,我們就可以通過讀取nodeType這個屬性來判斷這個節(jié)點的類型。在Java里,所有的屬性都是用getter來取得的,因此對某節(jié)點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()的結(jié)果比較,就可以知道它是不是某種類型。
Node接口中也定義了一些方法,比如:
?Node?????appendChild(in?Node?newChild)????raises(DOMException);
表明appendChild方法需要一個Node類型的參數(shù),返回一個Node。 具體的說明可以點文檔上的鏈接進去,也很容易看懂。
Node接口里定義了操縱節(jié)點的方法,比如增加子節(jié)點,返回父節(jié)點,插入新節(jié)點,返回節(jié)點類型,等等。Document,Element等接口都繼承Node接口,因此在它們上面都可以使用操縱節(jié)點的方法。
Document:代表整個XML文檔。所有DOM元素都不能用類似Java里new的方式來生成,而是要通過調(diào)用Document里的相應(yīng)方法來生成。因此它提供了生成諸如Element, Attr, Text的方法。比如createElement, createTextNode, createComment等。它也提供了名為getElementsByTagName的方法,用來通過標(biāo)簽名稱來取得其對象。比如getElementByTagName("ul")就可以獲得所有ul標(biāo)簽。它也提供一些文檔的屬性,比如xmlEncoding,inputEncoding等。它的一個屬性,documentElement代表文檔的根節(jié)點。所有對XML元素的操作,基本上都是從Document開始的。
Element:代表一個XML標(biāo)簽。它可以有屬性,子標(biāo)簽,等。比如<ul id="booklist"><li>hello</li></ul>。標(biāo)簽ul是一個Element,它有一個屬性叫id,屬性的值是booklist。它有一個子結(jié)點li。li也是一個標(biāo)簽,它也有個子節(jié)點hello,是一個Text類型的節(jié)點。這個接口提供操縱其標(biāo)簽屬性的方法,比如getAttribute,setAttribute,removeAttribute等。它也提供了和Document中一樣的getElementsByTagName的方法,用來獲得在這個節(jié)點下的元素。
Attr:代表標(biāo)簽中的屬性。比如上面的id。它也是一個Node。它有名字,值,也可以獲得它的所屬標(biāo)簽。
Text:代表一段文字,比如上面的hello,它也一個Node,但比較特殊,它不是直接繼承Node,而是繼承CharacterData接口,后者繼承了Node。但是它不能有子節(jié)點。
用JavaScript給一個例子。假設(shè)有一個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);
可以看到處理方式和數(shù)據(jù)類型都是一樣的。如果要了解更多,可以看看DOM的定義,都是IDL。