眾所周知窜管,SAX
與DOM
是JAVA中兩大核心XML解析API類庫揩尸,而JAXP
,JDOM
與DOM4J
都是基于這兩大核心API而衍生出來的宛渐。今日興起看了看相關(guān)資料,寫篇文章總結(jié)總結(jié).仿耽。
SAX與DOM
首先需要說明白的是SAX與DOM的關(guān)系合冀。
SAX
與DOM
都是底層API,在JDK中他們的包路徑分別為:org.xml.sax與org.w3c.dom项贺。自JDK1.5開始君躺,JDK中自帶的實(shí)現(xiàn)為Apache的xerces
(位于com.sun.org.apache.xerces.internal.parsers下)。
SAX
是Simple API for XML
的簡稱开缎,它是在JAVA平臺上第一個(gè)被廣泛使用的XML API棕叫。也就說它是為JAVA而出現(xiàn)的。目前已經(jīng)有多個(gè)語言版本奕删,比如C++俺泣。
DOM
是Documents Object Model
的簡稱,與SAX不同的是完残,DOM是W3C
的標(biāo)準(zhǔn)伏钠,它出現(xiàn)的目的是為了實(shí)現(xiàn)一套跨平臺與語言的標(biāo)準(zhǔn)。
以上是它們之間的第一個(gè)不同谨设。第二個(gè)熟掂,就是解析方式的不同。
SAX是基于事件解析
铝宵,解析過程中根據(jù)目前的XML元素類型打掘,調(diào)用用戶自己實(shí)現(xiàn)的回調(diào)方法(或著叫事件方法)來處理华畏,如:startDocument();
鹏秋,startElement();
尊蚁。
SAX2.0中有4個(gè)核心接口:
- org.xml.sax.ContentHander
- org.xml.sax.ErrorHandler
- org.xml.sax.DTDHandler
- org.xml.sax.EntityResolver
實(shí)現(xiàn)這幾個(gè)Handler,然后調(diào)用解析器相應(yīng)的set方法注冊給解析器侣夷,就可以完成各種元素的解析與處理横朋。 對應(yīng)的注冊進(jìn)解析器的方法分別是:
- parser.setContentHandler(ContentHander handler)
- parser.setErrorHandler(ErrorHandler handler)
- parser.setDTDHandler(DTDHandler handler)
完整例子:
DefaultHandler handler=new XmlParserHandler();//DefaultHandler已經(jīng)實(shí)現(xiàn)了全部org.xml.sax.ContentHandler,
//org.xml.sax.ErrortHandler百拓,org.xml.sax.DTDHandler和org.xml.sax.EntityHandler接口
XMLReader xr=XMLReaderFactory.createXMLReader();//獲取解析器實(shí)例
xr.setContentHandler(handler);//設(shè)置處理類
xr.setErrorHandler(handler);
xr.setDTDHandler(handler);
xr.setFeature("http://xml.org/sax/features/validation", true);//開啟DTD驗(yàn)證
xr.setFeature("http://apache.org/xml/features/validation/schema", true);//開啟SCHMAE驗(yàn)證
xr.parse(new InputSource("F:/Work/Workspace/XmlStudy/test.xml"));
基于事件處理的好處是琴锭,不需要等到整個(gè)XML文件被加載完成后在開始處理,而是加載到哪處理到哪衙传。這樣便帶來了效率上的優(yōu)勢决帖。但是其也有明顯的不足,第一個(gè)不足便是無法隨機(jī)訪問元素蓖捶。如果你只想獲取第二元素的信息地回,那么你必須等到第一個(gè)元素處理完成后,第二個(gè)元素開始的時(shí)候俊鱼。如果這時(shí)刻像,你又需要返回第一個(gè)元素,那么對不起并闲,已經(jīng)來不及了细睡。SAX不會主動記憶或保存已處理過的元素(為了效率)。為了實(shí)現(xiàn)前面的需求帝火,開發(fā)人員需要自己使用容器來保存處理過的元素溜徙,并且建立一個(gè)模型來表示XML的樹形結(jié)構(gòu)。這樣一來也就帶來了第二個(gè)缺點(diǎn)犀填,使用的復(fù)雜性萌京。
再來說說DOM。DOM采用了解析方式是一次性加載
整個(gè)XML文檔宏浩,在內(nèi)存中形成一個(gè)樹形的數(shù)據(jù)結(jié)構(gòu)知残,這個(gè)數(shù)據(jù)結(jié)構(gòu)我們稱為文檔對象模型。通過DOM解析器獲取Documen文檔t對象后比庄,開發(fā)人員可以很方便的對其進(jìn)行操作求妹,如getDocumentElement();(獲取更元素)
,getFirstChild();獲取一個(gè)子元素
佳窑,appendChild();增加子元素
制恍,removeChild();移除子元素
。因此神凑,使用DOM可以很方便對XML中的數(shù)據(jù)進(jìn)行獲取與修改净神,而不需要像SAX一樣自己設(shè)計(jì)模型保存獲取的數(shù)據(jù)何吝。
完整例子:
DOMParser dp=new DOMParser();
dp.parse(new InputSource("e:/test.xml"));
Document doc=dp.getDocument();
Element rootElemet=doc.getDocumentElement();
NodeList list=rootElemet.getChildNodes();
跟重要的一點(diǎn)是,在DOM中所有Element都是Node鹃唯,這意味著爱榕,我們不需要明確知道文檔的結(jié)構(gòu)就可以操作它。我們可以判斷當(dāng)前獲取到的任意Node對象類型來做不同操作坡慌。主要Node類型有:
- Node.DOCUMENT_NODE
- Node.ELEMENT_NODE
- Node.TEXT_NODE
- Node.CDATA_SECTION_NODE
- Node.PROCESSING_INSTRUCTION_NODE
- Node.ENTITY_REFERENCE_NODE
- Node.DOCUMENT_TYPE_NODE
但是黔酥,由于DOM是一次性加載整個(gè)XML文件到內(nèi)存, 如果XML文件非常龐大洪橘,構(gòu)建文檔樹的內(nèi)存與時(shí)間開銷會很大跪者,且很有可能導(dǎo)致內(nèi)存溢出異常。
那么如何在SAX與DOM直接選擇呢熄求?這取決于下面幾個(gè)因素:
- 應(yīng)用程序的目的:如果打算對數(shù)據(jù)作出更改并將它輸出為 XML渣玲,那么在大多數(shù)情況下,DOM 是適當(dāng)?shù)倪x擇弟晚。并不是說使用 SAX 就不能更改數(shù)據(jù)忘衍,但是該過程要復(fù)雜得多,因?yàn)槟仨殞?shù)據(jù)的一份拷貝而不是對數(shù)據(jù)本身作出更改指巡。
- 數(shù)據(jù)容量: 對于大型文件淑履,SAX 是更好的選擇。
- 數(shù)據(jù)將如何使用:如果只有數(shù)據(jù)中的少量部分會被使用藻雪,那么使用 SAX 來將該部分?jǐn)?shù)據(jù)提取到應(yīng)用程序中可能更好秘噪。 另一方面,如果您知道自己以后會回頭引用已處理過的大量信息勉耀,那么 SAX 也許不是恰當(dāng)?shù)倪x擇指煎。
- 對速度的需要: SAX 實(shí)現(xiàn)通常要比 DOM 實(shí)現(xiàn)更快。
SAX
和DOM
不是相互排斥的便斥,記住這點(diǎn)很重要至壤。您可以使用 DOM 來創(chuàng)建 SAX 事件流,也可以使用 SAX 來創(chuàng)建 DOM 樹枢纠。事實(shí)上像街,用于創(chuàng)建 DOM 樹的大多數(shù)解析器實(shí)際上都使用 SAX 來完成這個(gè)任務(wù),比如DOM4J
與JDOM
晋渺!
JAXP,JDOM與DOM4J
JAXP
JAXP
镰绎,全稱Java API for XML Processing
,打開其為JDK的目錄:javax.xml.parsers木西, 你會發(fā)現(xiàn)它與SAX和DOM一樣只是一套API畴栖。實(shí)際上,JAXP出現(xiàn)時(shí)SUN公司為了彌補(bǔ)JAVA在XML標(biāo)準(zhǔn)制定上的空白而制定的一套JAVA XML標(biāo)準(zhǔn)API八千。它并沒有為JAVA解析XML提供任何新功能吗讶,但是它為在JAVA獲取SAX與DOM解析器提供了更加直接的途徑燎猛。它封裝了SAX與DOM兩種接口,并在SAX與DOM的基礎(chǔ)之上照皆,作了一套比較簡單的api以供開發(fā)重绷。
例如:JAXP獲取SAX解析器:
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
parser.parse("F:/Work/Workspace/xiongqi/XmlStudy/test.xml", handler);
獲取DOM解析器:
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder= factory.newDocumentBuilder();
Document document= builder.parse("F:/Work/Workspace/xiongqi/XmlStudy/test.xml");
在 JAXP 的早期版本中,自帶解析器的實(shí)現(xiàn)為 Apachede 的Crimson纵寝,在 JAXP 的新版本中 (包括在 JDK 中) 论寨,Sun 已經(jīng)重新包裝了 Apache Xerces 做為解析器的實(shí)現(xiàn)星立。
JDOM
由于DOM是為了實(shí)現(xiàn)一套跨平臺與語言的標(biāo)準(zhǔn)爽茴,因此使用它對于JAVA開發(fā)人員來說并不是特別的得心應(yīng)手,這時(shí)JDOM
就出現(xiàn)了绰垂。
JDOM
的目的是成為 Java 特定文檔模型室奏,它簡化與 XML 的交互并且比使用 DOM 實(shí)現(xiàn)更快。而且它是第一個(gè) Java 特定模型劲装。與DOM
相比較胧沫,首先,JDOM 僅使用具體類而不使用接口占业。這在某些方面簡化了API绒怨,但是也限制了靈活性。第二谦疾,API 大量使用了 Collections 類南蹂,相對于dom中的Node,簡化了那些已經(jīng)熟悉這些類的Java 開發(fā)者的使用念恍。JDOM 自身不包含解析器六剥,默認(rèn)使用隨jar包一起發(fā)行的pache Xerces。
例子:
SAXBuilder builder = new SAXBuilder(false);
Document doc = builder.build(in);
從上面代碼中可以看出峰伙,JDOM使用SAX2 解析器來解析和驗(yàn)證輸入 XML 文檔疗疟,然后構(gòu)建Doucment對象。
DOM4J
DOM4J
最初是 JDOM 的一個(gè)分支瞳氓。它合并了許多超出基本 XML 文檔表示的功能策彤,包括集成的 XPath 支持、XML Schema 支持以及用于大文檔或流化文檔的基于事件的處理匣摘。它還提供了構(gòu)建文檔表示的選項(xiàng)店诗,它通過 DOM4J API 和標(biāo)準(zhǔn) DOM 接口具有并行訪問功能。
為支持所有這些功能恋沃,DOM4J 使用接口
和抽象
基本類方法必搞。DOM4J 大量使用了 API 中的Collections 類,但是在許多情況下囊咏,它還提供一些替代方法以允許更好的性能或更直接的編碼方法恕洲。直接好處是塔橡,雖然 DOM4J 付出了更復(fù)雜的 API 的代價(jià),但是它提供了比 JDOM 大得多的靈活性霜第。在添加靈活性葛家、XPath 集成和對大文檔處理的目標(biāo)時(shí),DOM4J 的目標(biāo)與 JDOM 是一樣的:針對 Java開發(fā)者的易用性和直觀操作泌类。它還致力于成為比 JDOM 更完整的解決方案癞谒,實(shí)現(xiàn)在本質(zhì)上處理所有Java/XML 問題的目標(biāo)。在完成該目標(biāo)時(shí)刃榨,它比 JDOM 更少強(qiáng)調(diào)防止不正確的應(yīng)用程序行為弹砚。
例子:
SAXReader reader = new SAXReader(false);
Document doc = reader.read(in);
DOM4J 是一個(gè)非常非常優(yōu)秀的Java XML API,具有性能優(yōu)異枢希、功能強(qiáng)大和極端易用使用的特點(diǎn)桌吃,同時(shí)它也是一個(gè)開放源代碼的軟件。如今你可以看到越來越多的 Java 軟件都在使用 DOM4J 來讀寫 XML苞轿,特別值得一提的是連 Sun 的 JAXM 也在用 DOM4J茅诱。