預備
測試環(huán)境:
amd毒龍1.4g oc 1.5g、256m ddr333、windows2000 server sp4、sun jdk 1.4.1+eclipse 2.1+resin 2.1.8,在debug模式下測試。
xml文件格式如下:
?。?xml version="1.0" encoding="gb2312"?><result><value>
?。糿o>a1234</no>
?。糰ddr>四川省xx縣xx鎮xx路x段xx號</addr></value><value>
?。糿o>b1234</no>
?。糰ddr>四川省xx市xx鄉xx村xx組</addr></value></result>
測試方法:
采用jsp端調用bean(至于為什么采用jsp來(lái)調用,請參考:http://blog.csdn.net/rosen/archive/2004/10/15/138324.aspx),讓每一種方案分別解析10k、100k、1000k、10000k的xml文件,計算其消耗時(shí)間(單位:毫秒)。
jsp文件:
?。?@ page contenttype="text/html; charset=gb2312" %><%@ page import="com.test.*"%>
?。糷tml><body><%string args[]={""};myxmlreader.main(args);%></body></html>
測試
首先出場(chǎng)的是dom(jaxp crimson解析器)
dom是用與平臺和語(yǔ)言無(wú)關(guān)的方式表示xml文檔的官方w3c標準。dom是以層次結構組織的節點(diǎn)或信息片斷的集合。這個(gè)層次結構允許開(kāi)發(fā)人員在樹(shù)中尋找特定信息。分析該結構通常需要加載整個(gè)文檔和構造層次結構,然后才能做任何工作。由于它是基于信息層次的,因而dom被認為是基于樹(shù)或基于對象的。dom以及廣義的基于樹(shù)的處理具有幾個(gè)優(yōu)點(diǎn)。首先,由于樹(shù)在內存中是持久的,因此可以修改它以便應用程序能對數據和結構作出更改。它還可以在任何時(shí)候在樹(shù)中上下導航,而不是像sax那樣是一次性的處理。dom使用起來(lái)也要簡(jiǎn)單得多。
另一方面,對于特別大的文檔,解析和加載整個(gè)文檔可能很慢且很耗資源,因此使用其他手段來(lái)處理這樣的數據會(huì )更好。這些基于事件的模型,比如sax。
bean文件:
package com.test;
import java.io.*;import java.util.*;import org.w3c.dom.*;import javax.xml.parsers.*;
public class myxmlreader{
public static void main(string arge[]){
long lasting =system.currenttimemillis();
try{
file f=new file("data_10k.xml");
documentbuilderfactory factory=documentbuilderfactory.newinstance();
documentbuilder builder=factory.newdocumentbuilder();
document doc = builder.parse(f);
nodelist nl = doc.getelementsbytagname("value");
for (int i=0;i<nl.getlength();i++){
system.out.print("車(chē)牌號碼:" + doc.getelementsbytagname("no").item(i).getfirstchild().getnodevalue());
system.out.println("車(chē)主地址:" + doc.getelementsbytagname("addr").item(i).getfirstchild().getnodevalue());
}
}catch(exception e){
e.printstacktrace();
}
system.out.println("運行時(shí)間:"+(system.currenttimemillis() - lasting)+"毫秒");}}
10k消耗時(shí)間:265 203 219 172
100k消耗時(shí)間:9172 9016 8891 9000
1000k消耗時(shí)間:691719 675407 708375 739656
10000k消耗時(shí)間:outofmemoryerror
接著(zhù)是sax
這種處理的優(yōu)點(diǎn)非常類(lèi)似于流媒體的優(yōu)點(diǎn)。分析能夠立即開(kāi)始,而不是等待所有的數據被處理。而且,由于應用程序只是在讀取數據時(shí)檢查數據,因此不需要將數據存儲在內存中。這對于大型文檔來(lái)說(shuō)是個(gè)巨大的優(yōu)點(diǎn)。事實(shí)上,應用程序甚至不必解析整個(gè)文檔;它可以在某個(gè)條件得到滿(mǎn)足時(shí)停止解析。一般來(lái)說(shuō),sax還比它的替代者dom快許多。
選擇dom還是選擇sax?
對于需要自己編寫(xiě)代碼來(lái)處理xml文檔的開(kāi)發(fā)人員來(lái)說(shuō),
選擇dom還是sax解析模型是一個(gè)非常重要的設計決策。
dom采用建立樹(shù)形結構的方式訪(fǎng)問(wèn)xml文檔,而sax采用的事件模型。
dom解析器把xml文檔轉化為一個(gè)包含其內容的樹(shù),并可以對樹(shù)進(jìn)行遍歷。用dom解析模型的優(yōu)點(diǎn)是編程容易,開(kāi)發(fā)人員只需要調用建樹(shù)的指令,然后利用navigation apis訪(fǎng)問(wèn)所需的樹(shù)節點(diǎn)來(lái)完成任務(wù)??梢院苋菀椎奶砑雍托薷臉?shù)中的元素。然而由于使用dom解析器的時(shí)候需要處理整個(gè)xml文檔,所以對性能和內存的要求比較高,尤其是遇到很大的xml文件的時(shí)候。由于它的遍歷能力,dom解析器常用于xml文檔需要頻繁的改變的服務(wù)中。
sax解析器采用了基于事件的模型,它在解析xml文檔的時(shí)候可以觸發(fā)一系列的事件,當發(fā)現給定的tag的時(shí)候,它可以激活一個(gè)回調方法,告訴該方法制定的標簽已經(jīng)找到。sax對內存的要求通常會(huì )比較低,因為它讓開(kāi)發(fā)人員自己來(lái)決定所要處理的tag。特別是當開(kāi)發(fā)人員只需要處理文檔中所包含的部分數據時(shí),sax這種擴展能力得到了更好的體現。但用sax解析器的時(shí)候編碼工作會(huì )比較困難,而且很難同時(shí)訪(fǎng)問(wèn)同一個(gè)文檔中的多處不同數據。
bean文件:
package com.test;import org.xml.sax.*;import org.xml.sax.helpers.*;import javax.xml.parsers.*;
public class myxmlreader extends defaulthandler {
java.util.stack tags = new java.util.stack();
public myxmlreader() {
super();}
public static void main(string args[]) {
long lasting = system.currenttimemillis();
try {
saxparserfactory sf = saxparserfactory.newinstance();
saxparser sp = sf.newsaxparser();
myxmlreader reader = new myxmlreader();
sp.parse(new inputsource("data_10k.xml"), reader);
} catch (exception e) {
e.printstacktrace();
}
system.out.println("運行時(shí)間:" + (system.currenttimemillis() - lasting) + "毫秒");}
public void characters(char ch[], int start, int length) throws saxexception {
string tag = (string) tags.peek();
if (tag.equals("no")) {
system.out.print("車(chē)牌號碼:" + new string(ch, start, length));}if (tag.equals("addr")) {
system.out.println("地址:" + new string(ch, start, length));}}
public void startelement(string uri,string localname,string qname,attributes attrs) {
tags.push(qname);}}
10k消耗時(shí)間:110 47 109 78
100k消耗時(shí)間:344 406 375 422
1000k消耗時(shí)間:3234 3281 3688 3312
10000k消耗時(shí)間:32578 34313 31797 31890 30328
然后是jdom http://www.jdom.org/
jdom的目的是成為java特定文檔模型,它簡(jiǎn)化與xml的交互并且比使用dom實(shí)現更快。由于是第一個(gè)java特定模型,jdom一直得到大力推廣和促進(jìn)。正在考慮通過(guò)“java規范請求jsr-102”將它最終用作“java標準擴展”。從2000年初就已經(jīng)開(kāi)始了jdom開(kāi)發(fā)。
jdom與dom主要有兩方面不同。首先,jdom僅使用具體類(lèi)而不使用接口。這在某些方面簡(jiǎn)化了api,但是也限制了靈活性。第二,api大量使用了collections類(lèi),簡(jiǎn)化了那些已經(jīng)熟悉這些類(lèi)的java開(kāi)發(fā)者的使用。
jdom文檔聲明其目的是“使用20%(或更少)的精力解決80%(或更多)java/xml問(wèn)題”(根據學(xué)習曲線(xiàn)假定為20%)。jdom對于大多數java/xml應用程序來(lái)說(shuō)當然是有用的,并且大多數開(kāi)發(fā)者發(fā)現api比dom容易理解得多。jdom還包括對程序行為的相當廣泛檢查以防止用戶(hù)做任何在xml中無(wú)意義的事。然而,它仍需要您充分理解xml以便做一些超出基本的工作(或者甚至理解某些情況下的錯誤)。這也許是比學(xué)習dom或jdom接口都更有意義的工作。
jdom自身不包含解析器。它通常使用sax2解析器來(lái)解析和驗證輸入xml文檔(盡管它還可以將以前構造的dom表示作為輸入)。它包含一些轉換器以將jdom表示輸出成sax2事件流、dom模型或xml文本文檔。jdom是在apache許可證變體下發(fā)布的開(kāi)放源碼。
bean文件:
package com.test;
import java.io.*;import java.util.*;import org.jdom.*;import org.jdom.input.*;
public class myxmlreader {
public static void main(string arge[]) {
long lasting = system.currenttimemillis();
try {
saxbuilder builder = new saxbuilder();
document doc = builder.build(new file("data_10k.xml"));
element foo = doc.getrootelement();
list allchildren = foo.getchildren();
for(int i=0;i<allchildren.size();i++) {
system.out.print("車(chē)牌號碼:" + ((element)allchildren.get(i)).getchild("no").gettext());
system.out.println("車(chē)主地址:" + ((element)allchildren.get(i)).getchild("addr").gettext());
}
} catch (exception e) {
e.printstacktrace();
}
system.out.println("運行時(shí)間:" + (system.currenttimemillis() - lasting) + "毫秒");}}
10k消耗時(shí)間:125 62 187 94
100k消耗時(shí)間:704 625 640 766
1000k消耗時(shí)間:27984 30750 27859 30656
10000k消耗時(shí)間:outofmemoryerror
最后是dom4j http://dom4j.sourceforge.net/
雖然dom4j代表了完全獨立的開(kāi)發(fā)結果,但最初,它是jdom的一種智能分支。它合并了許多超出基本xml文檔表示的功能,包括集成的xpath支持、xml schema支持以及用于大文檔或流化文檔的基于事件的處理。它還提供了構建文檔表示的選項,它通過(guò)dom4j api和標準dom接口具有并行訪(fǎng)問(wèn)功能。從2000下半年開(kāi)始,它就一直處于開(kāi)發(fā)之中。
為支持所有這些功能,dom4j使用接口和抽象基本類(lèi)方法。dom4j大量使用了api中的collections類(lèi),但是在許多情況下,它還提供一些替代方法以允許更好的性能或更直接的編碼方法。直接好處是,雖然dom4j付出了更復雜的api的代價(jià),但是它提供了比jdom大得多的靈活性。
在添加靈活性、xpath集成和對大文檔處理的目標時(shí),dom4j的目標與jdom是一樣的:針對java開(kāi)發(fā)者的易用性和直觀(guān)操作。它還致力于成為比jdom更完整的解決方案,實(shí)現在本質(zhì)上處理所有java/xml問(wèn)題的目標。在完成該目標時(shí),它比jdom更少強調防止不正確的應用程序行為。
dom4j是一個(gè)非常非常優(yōu)秀的java xml api,具有性能優(yōu)異、功能強大和極端易用使用的特點(diǎn),同時(shí)它也是一個(gè)開(kāi)放源代碼的軟件。如今你可以看到越來(lái)越多的java軟件都在使用dom4j來(lái)讀寫(xiě)xml,特別值得一提的是連sun的jaxm也在用dom4j。
bean文件:
package com.test;
import java.io.*;import java.util.*;import org.dom4j.*;import org.dom4j.io.*;
public class myxmlreader {
public static void main(string arge[]) {
long lasting = system.currenttimemillis();
try {
file f = new file("data_10k.xml");
saxreader reader = new saxreader();
document doc = reader.read(f);
element root = doc.getrootelement();
element foo;
for (iterator i = root.elementiterator("value"); i.hasnext();) {
foo = (element) i.next();
system.out.print("車(chē)牌號碼:" + foo.elementtext("no"));
system.out.println("車(chē)主地址:" + foo.elementtext("addr"));
}
} catch (exception e) {
e.printstacktrace();
}
system.out.println("運行時(shí)間:" + (system.currenttimemillis() - lasting) + "毫秒");}}
10k消耗時(shí)間:109 78 109 31
100k消耗時(shí)間:297 359 172 312
1000k消耗時(shí)間:2281 2359 2344 2469
10000k消耗時(shí)間:20938 19922 20031 21078
jdom和dom在性能測試時(shí)表現不佳,在測試10m文檔時(shí)內存溢出。在小文檔情況下還值得考慮使用dom和jdom。雖然jdom的開(kāi)發(fā)者已經(jīng)說(shuō)明他們期望在正式發(fā)行版前專(zhuān)注性能問(wèn)題,但是從性能觀(guān)點(diǎn)來(lái)看,它確實(shí)沒(méi)有值得推薦之處。另外,dom仍是一個(gè)非常好的選擇。dom實(shí)現廣泛應用于多種編程語(yǔ)言。它還是許多其它與xml相關(guān)的標準的基礎,因為它正式獲得w3c推薦(與基于非標準的java模型相對),所以在某些類(lèi)型的項目中可能也需要它(如在javascript中使用dom)。
sax表現較好,這要依賴(lài)于它特定的解析方式。一個(gè)sax檢測即將到來(lái)的xml流,但并沒(méi)有載入到內存(當然當xml流被讀入時(shí),會(huì )有部分文檔暫時(shí)隱藏在內存中)。
無(wú)疑,dom4j是這場(chǎng)測試的獲勝者,目前許多開(kāi)源項目中大量采用dom4j,例如大名鼎鼎的hibernate也用dom4j來(lái)讀取xml配置文件。如果不考慮可移植性,那就采用dom4j吧!(文/rosen)
文章整理:站長(cháng)天空 網(wǎng)址:http://www.z6688.com/
以上信息與文章正文是不可分割的一部分,如果您要轉載本文章,請保留以上信息,謝謝!

