2007-07-15 11:33
關(guān)于JAXP,DOM,SAX,JDOM,DOM4J的一些想法
這些API是XSLT的關(guān)鍵部分,它們構(gòu)建在DOM和SAX解析器基礎(chǔ)上。
Sun在XML領(lǐng)域總是后知后覺,等到Sun重視XML的時(shí)候,XML的API早就滿天飛了,尤其是IBM具有非常大的領(lǐng)先優(yōu)勢。不過Sun是規(guī)范
的制訂者,于是參考WOffice:smarttags"
/>3C的標(biāo)準(zhǔn)制訂了JAXP規(guī)范。JAXP不像Xerces和Crimon那樣,它只是一個(gè)spec,本身是不做任何事情的,它的作用就是提出一
個(gè)統(tǒng)一的接口,讓其它的XML API都來遵循JAXP編程,那么用JAXP寫出來的程序,底層的API可以任意切換。
具體來說JAXP包括了幾個(gè)工廠類,這就是JDK1.4里面的Javax.xml.parsers 包,用來尋找符合DOM標(biāo)準(zhǔn)的XML
API實(shí)現(xiàn)類的位置;此外JAXP還包括一整套interface,這就是JDK1.4里面的org.w3c.dom那幾個(gè)包。工廠類負(fù)責(zé)加載DOM的實(shí)
現(xiàn)類。
當(dāng)你嚴(yán)格采用JAXP編程的時(shí)候,是遵循W3C的DOm標(biāo)準(zhǔn)的,那么在JAXP底層你實(shí)際上可以任意切換不同的DOM實(shí)現(xiàn),例如Xerces,或者Crimon,再或者其它,切換方法就是配置jaxp.properties。因此JAXP就是一些標(biāo)準(zhǔn)接口而已。
JAXP應(yīng)用程序 -> JAXP接口 -> Xerces DOM實(shí)現(xiàn) -> Xerces DOM/SAX 解析器
JAXP應(yīng)用程序 -> JAXP接口 -> Crimson DOM實(shí)現(xiàn) -> Crimson DOM/SAX 解析器
JAXP應(yīng)用程序 -> JAXP接口 -> Crimson DOM實(shí)現(xiàn) -> Xerces DOM/SAX 解析器
W3C的DOM標(biāo)準(zhǔn)API難用的讓人想撞墻,于是有一幫人開發(fā)Java專用的XML
API目的是為了便于使用,這就是jdom的由來,開發(fā)到一半的時(shí)候,另一部分人又分了出來,他們有自己的想法,于是他們就去開發(fā)dom4j,形成了今天
這樣兩個(gè)API,至于他們之間的性能,功能之比較看看上面我推薦的文章就知道了,jdom全面慘敗。
jdom 相當(dāng)于上面的 JAXP接口 + Xerces DOM實(shí)現(xiàn)部分,它本身沒有解析器,它可以使用Xerces或者Crimson的解析器即
JAXP應(yīng)用程序 -> JAXP接口 -> Xerces DOM實(shí)現(xiàn) -> Crimson DOM/SAX 解析器 或 Xerces DOM/SAX 解析器
jdom應(yīng)用程序 -> jdom API -> Xerces/Crimson解析器
dom4j應(yīng)用程序 -> dom4j API -> Xerces/Crimson解析器
dom4j應(yīng)用程序 -> dom4j API -> Alfred2解析器
因此可以看出采用dom4j/jdom編寫的應(yīng)用程序,已經(jīng)不具備可移植性了。
Sun是JAXP標(biāo)準(zhǔn)的制訂者,甚至很執(zhí)著的在JDK1.4里面綁定Crimson DOM實(shí)現(xiàn)和解析器,然后可笑的是,Sun自己的JAXM RI竟然不是用JAXP寫出來的,而是dom4j
我的舉例:
1. 僅僅是XSL轉(zhuǎn)換。XMLàHTML,通過XSL
Import javax.xml.transform.TransformerFactory;
Import javax.xml.transform.Transformer;
Import javax.xml.stream.StreamSource;
Import javax.xml.stream.StreamResult;
import java.io.FileOutputStream;
TransformerFactory transFactory = TransformerFactory.newInstance();
Transform transformer = transFacyory.newTransformer(new StreamSource(XMLSheetName));
Transformer.transform(new StreamSource(XMLFileName),new StreamResult(new FileOutputStream(outputURL)));
這里的stream是一個(gè)DOM對象。
我感覺這個(gè)就是JAXP應(yīng)用程序 -> JAXP接口 -> Xerces DOM實(shí)現(xiàn) -> Xerces DOM/SAX 解析器,不知道對不對。
2.遍歷XML,通過DOM。不僅僅是XSL轉(zhuǎn)換。中間有對XML元素內(nèi)容的操作。
Import javax.xml.transform.TransformerFactory;
Import javax.xml.transform.Transformer;
Import javax.xml.stream.StreamSource;
Import javax.xml.stream.StreamResult;
import java.io.FileOutputStream;
//Xerces解析器來完成DOM遍歷XML.DOMParser是Xerces包的一部分。
Import org.apache.xerces.parsers.DOMParser;
Import org.w3c.dom.Document;
Import org.w3c.dom.NodeList;
//DOM遍歷XML
DOMParser parser = new DOMParser();
Parser.parse(XMLFileName);//解析并在內(nèi)存中創(chuàng)建XML樹。
Document document = parser.getDocument();//通過Document對象,可以使用內(nèi)存中的樹。
NodeList products = document.getElementByTagName(“product_id”);
Int num_products = products.getLength();
//XSL轉(zhuǎn)化器
TransformerFactory transFactory = TransformerFactory.newInstance();
Transform transformer = transFacyory.newTransformer(new StreamSource(XMLSheetName));
Transformer.transform(new StreamSource(XMLFileName),new StreamResult(new FileOutputStream(outputURL)));
我感覺XSL轉(zhuǎn)化和對XML對象的操作是兩個(gè)過程。可以分別對待。最重要的是對對象的操作。這也就是為什么有DOM,JDOM,DOM4J。轉(zhuǎn)化好像只需要JAXP就可以了,關(guān)心的是StreamSource和StreamResult。這兩個(gè)是DOM對象。
3.JDOM使用,生成Document內(nèi)容并保存到XML文件。
import org.jdom.Element;
import org.jdom.Document;//和Import org.w3c.dom.Document對比一下。一個(gè)是JAXP的一個(gè)是JDOM的Document
import org.jdom.output.XMLOutputter;
Element root = Element(“orders”);
root.addContent(“ ”);
org.jdom.Document document = new Document(root);//創(chuàng)建JDOM樹。
FileOutputStream outStream = new FileOutputStream(XMLFileName);
XMLOutputter outToFile = new XMLOutputter();
outToFile.output(document,outStream);
outStream.flush();
outStream.close();
jdom應(yīng)用程序 -> jdom API -> Xerces/Crimson解析器
VS
JAXP應(yīng)用程序 -> JAXP接口 -> Xerces DOM實(shí)現(xiàn) -> Xerces DOM/SAX 解析器
這里的沒有Transform的過程,直接把Document的內(nèi)容存到XML中。沒有XSL轉(zhuǎn)化,沒有XSL文件。
JDOM提供了幾種輸出方法。這里XMLOutputter是保存到文件,輸出一個(gè)實(shí)際的XML流。還有DOMOutputter,在內(nèi)存中創(chuàng)建一個(gè)傳統(tǒng)的DOM樹。還有SAXOutputter,創(chuàng)建一串SAX事件以便被其他對象讀取。
4.JDOM使用,讀取已有的XML然后生成Document,修改Document
import org.jdom.Element;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
import org.jdom.input.SAXBuilder;
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(XMLFileName);
Element order = Element(“orders”);
orders.addAttribute(“order_id”,session_id);
Element root = document.getRootElement();//root是已經(jīng)存在的根元素。
Root.addContent(order);//在根元素里增加orders元素。
//把document保存到文件中。
FileOutputStream outStream = new FileOutputStream(XMLFileName);
XMLOutputter outToFile = new XMLOutputter();
outToFile.output(document,outStream);
outStream.flush();
outStream.close();
即使創(chuàng)建一個(gè)DOM式的結(jié)構(gòu),這里仍使用SAXBuilder來做這這件事情。
DOMBuilder和SAXBuilder中的”DOM”和”SAX”指的是用于建立文檔的方法,而不是生成的內(nèi)容。
5.XSL轉(zhuǎn)換,能把DOM對象轉(zhuǎn)化成輸出,也可以向上面所舉例的把XMLFileName的流轉(zhuǎn)化成輸出的流(文件或屏幕顯示)。但是不能把JDOM對象轉(zhuǎn)化,所以需要把JDOM轉(zhuǎn)化成DOM對象,然后再輸出。
import org.jdom.Element;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
import org.jdom.input.SAXBuilder;
//XSL轉(zhuǎn)化需要的包
import org.jdom.output.DOMOutputter;//對比org.jdom.output.XMLOutputter;
Import javax.xml.transform.TransformerFactory;
Import javax.xml.transform.Transformer;
Import javax.xml.transform.DOMSource;//對比Import javax.xml.stream.StreamSource;
Import javax.xml.stream.StreamResult;
org.w3c.dom.Document DOMDoc;
DOMOutputter DomOut = DOMOutputter();
DOMDoc = DomOut.output(org.jdom.Document);//把jdom的document轉(zhuǎn)化成DOM的document
TransformFactory transFactory = TransformFactory.newInstance();
Transformer transformer = transFactory.newTransformer(new DOMSource(DOMDoc));//感覺錯了,應(yīng)該是XSL文件。
Transformer.transform(new DOMSource(DOMDoc),new StreamResult(out));
//對比以前的轉(zhuǎn)化,是從文件到文件,現(xiàn)在是DOM樹到屏幕輸出。
TransformerFactory transFactory = TransformerFactory.newInstance();
Transform transformer = transFacyory.newTransformer(new StreamSource(XMLSheetName));
Transformer.transform(new StreamSource(XMLFileName),new StreamResult(new FileOutputStream(outputURL)));