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。