Dom4j 使用簡(jiǎn)介
作者:冰云 icecloud(AT)sina.com
時(shí)間:2003.12.15
版權(quán)聲明:
本文由冰云完成,首發(fā)于CSDN,未經(jīng)許可,不得使用于任何商業(yè)用途。
文中代碼部分引用自DOM4J文檔。
歡迎轉(zhuǎn)載,但請(qǐng)保持文章及版權(quán)聲明完整。
如需聯(lián)絡(luò)請(qǐng)發(fā)郵件:icecloud(AT)sina.com
DOM4J是dom4j.org出品的一個(gè)開(kāi)源XML解析包,它的網(wǎng)站中這樣定義:
Dom4j is an easy to use, open source library for working with XML, XPath and XSLT on the Java platform using the Java Collections Framework and with full support for DOM, SAX and JAXP.
Dom4j是一個(gè)易用的、開(kāi)源的庫(kù),用于XML,XPath和XSLT。它應(yīng)用于Java平臺(tái),采用了Java集合框架并完全支持DOM,SAX和JAXP。
DOM4J使用起來(lái)非常簡(jiǎn)單。只要你了解基本的XML-DOM模型,就能使用。然而他自己帶的指南只有短短一頁(yè)(html),不過(guò)說(shuō)的到挺全。國(guó)內(nèi)的中文資料很少。因而俺寫這個(gè)短小的教程方便大家使用,這篇文章僅談及基本的用法,如需深入的使用,請(qǐng)……自己摸索或查找別的資料。
之前看過(guò)IBM developer社區(qū)的文章(參見(jiàn)附錄),提到一些XML解析包的性能比較,其中DOM4J的性能非常出色,在多項(xiàng)測(cè)試中名列前茅。(事實(shí)上DOM4J的官方文檔中也引用了這個(gè)比較)所以這次的項(xiàng)目中我采用了DOM4J作為XML解析工具。
在國(guó)內(nèi)比較流行的是使用JDOM作為解析器,兩者各擅其長(zhǎng),但DOM4J最大的特色是使用大量的接口,這也是它被認(rèn)為比JDOM靈活的主要原因。大師不是說(shuō)過(guò)么,“面向接口編程”。目前使用DOM4J的已經(jīng)越來(lái)越多。如果你善于使用JDOM,不妨繼續(xù)用下去,只看看本篇文章作為了解與比較,如果你正要采用一種解析器,不如就用DOM4J吧。
它的主要接口都在org.dom4j這個(gè)包里定義:
Attribute
Attribute定義了XML的屬性
Branch
Branch為能夠包含子節(jié)點(diǎn)的節(jié)點(diǎn)如XML元素(Element)和文檔(Docuemnts)定義了一個(gè)公共的行為,
CDATA
CDATA 定義了XML CDATA 區(qū)域
CharacterData
CharacterData是一個(gè)標(biāo)識(shí)借口,標(biāo)識(shí)基于字符的節(jié)點(diǎn)。如CDATA,Comment, Text.
Comment
Comment 定義了XML注釋的行為
Document
定義了XML文檔
DocumentType
DocumentType 定義XML DOCTYPE聲明
Element
Element定義XML 元素
ElementHandler
ElementHandler定義了 Element 對(duì)象的處理器
ElementPath
被 ElementHandler 使用,用于取得當(dāng)前正在處理的路徑層次信息
Entity
Entity定義 XML entity
Node
Node為所有的dom4j中XML節(jié)點(diǎn)定義了多態(tài)行為
NodeFilter
NodeFilter 定義了在dom4j節(jié)點(diǎn)中產(chǎn)生的一個(gè)濾鏡或謂詞的行為(predicate)
ProcessingInstruction
ProcessingInstruction 定義 XML 處理指令.
Text
Text 定義XML 文本節(jié)點(diǎn).
Visitor
Visitor 用于實(shí)現(xiàn)Visitor模式.
XPath
XPath 在分析一個(gè)字符串后會(huì)提供一個(gè)XPath 表達(dá)式
看名字大致就知道它們的涵義如何了。
要想弄懂這套接口,關(guān)鍵的是要明白接口的繼承關(guān)系:
interface java.lang.Cloneable
interface org.dom4j.Node
interface org.dom4j.Attribute
interface org.dom4j.Branch
interface org.dom4j.Document
interface org.dom4j.Element
interface org.dom4j.CharacterData
interface org.dom4j.CDATA
interface org.dom4j.Comment
interface org.dom4j.Text
interface org.dom4j.DocumentType
interface org.dom4j.Entity
interface org.dom4j.ProcessingInstruction
一目了然,很多事情都清楚了。大部分都是由Node繼承來(lái)的。知道這些關(guān)系,將來(lái)寫程序就不會(huì)出現(xiàn)ClassCastException了。
下面給出一些例子(部分摘自DOM4J自帶的文檔),簡(jiǎn)單說(shuō)一下如何使用。
1. 讀取并解析XML文檔:
讀寫XML文檔主要依賴于org.dom4j.io包,其中提供DOMReader和SAXReader兩類不同方式,而調(diào)用方式是一樣的。這就是依靠接口的好處。
// 從文件讀取XML,輸入文件名,返回XML文檔
public Document read(String fileName) throws MalformedURLException, DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(new File(fileName));
return document;
}
其中,reader的read方法是重載的,可以從InputStream, File, Url等多種不同的源來(lái)讀取。得到的Document對(duì)象就帶表了整個(gè)XML。
根據(jù)本人自己的經(jīng)驗(yàn),讀取的字符編碼是按照XML文件頭定義的編碼來(lái)轉(zhuǎn)換。如果遇到亂碼問(wèn)題,注意要把各處的編碼名稱保持一致即可。
2. 取得Root節(jié)點(diǎn)
讀取后的第二步,就是得到Root節(jié)點(diǎn)。熟悉XML的人都知道,一切XML分析都是從Root元素開(kāi)始的。
public Element getRootElement(Document doc){
return doc.getRootElement();
}
3. 遍歷XML樹(shù)
DOM4J提供至少3種遍歷節(jié)點(diǎn)的方法:
1) 枚舉(Iterator)
// 枚舉所有子節(jié)點(diǎn)
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
Element element = (Element) i.next();
// do something
}
// 枚舉名稱為foo的節(jié)點(diǎn)
for ( Iterator i = root.elementIterator(foo); i.hasNext();) {
Element foo = (Element) i.next();
// do something
}
// 枚舉屬性
for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
Attribute attribute = (Attribute) i.next();
// do something
}
2)遞歸
遞歸也可以采用Iterator作為枚舉手段,但文檔中提供了另外的做法
public void treeWalk() {
treeWalk(getRootElement());
}
public void treeWalk(Element element) {
for (int i = 0, size = element.nodeCount(); i < size; i++) {
Node node = element.node(i);
if (node instanceof Element) {
treeWalk((Element) node);
} else { // do something....
}
}
}
3) Visitor模式
最令人興奮的是DOM4J對(duì)Visitor的支持,這樣可以大大縮減代碼量,并且清楚易懂。了解設(shè)計(jì)模式的人都知道,Visitor是GOF設(shè)計(jì)模式之一。其主要原理就是兩種類互相保有對(duì)方的引用,并且一種作為Visitor去訪問(wèn)許多Visitable。我們來(lái)看DOM4J中的Visitor模式(快速文檔中沒(méi)有提供)
只需要自定一個(gè)類實(shí)現(xiàn)Visitor接口即可。
public class MyVisitor extends VisitorSupport {
public void visit(Element element){
System.out.println(element.getName());
}
public void visit(Attribute attr){
System.out.println(attr.getName());
}
}
調(diào)用: root.accept(new MyVisitor())
Visitor接口提供多種Visit()的重載,根據(jù)XML不同的對(duì)象,將采用不同的方式來(lái)訪問(wèn)。上面是給出的Element和Attribute的簡(jiǎn)單實(shí)現(xiàn),一般比較常用的就是這兩個(gè)。VisitorSupport是DOM4J提供的默認(rèn)適配器,Visitor接口的Default Adapter模式,這個(gè)模式給出了各種visit(*)的空實(shí)現(xiàn),以便簡(jiǎn)化代碼。
注意,這個(gè)Visitor是自動(dòng)遍歷所有子節(jié)點(diǎn)的。如果是root.accept(MyVisitor),將遍歷子節(jié)點(diǎn)。我第一次用的時(shí)候,認(rèn)為是需要自己遍歷,便在遞歸中調(diào)用Visitor,結(jié)果可想而知。
4. XPath支持
DOM4J對(duì)XPath有良好的支持,如訪問(wèn)一個(gè)節(jié)點(diǎn),可直接用XPath選擇。
public void bar(Document document) {
List list = document.selectNodes( //foo/bar );
Node node = document.selectSingleNode(//foo/bar/author);
String name = node.valueOf( @name );
}
例如,如果你想查找XHTML文檔中所有的超鏈接,下面的代碼可以實(shí)現(xiàn):
public void findLinks(Document document) throws DocumentException {
List list = document.selectNodes( //a/@href );
for (Iterator iter = list.iterator(); iter.hasNext(); ) {
Attribute attribute = (Attribute) iter.next();
String url = attribute.getValue();
}
}
5. 字符串與XML的轉(zhuǎn)換
有時(shí)候經(jīng)常要用到字符串轉(zhuǎn)換為XML或反之,
// XML轉(zhuǎn)字符串
Document document = ...;
String text = document.asXML();
// 字符串轉(zhuǎn)XML
String text = <person> <name>James</name> </person>;
Document document = DocumentHelper.parseText(text);
6 用XSLT轉(zhuǎn)換XML
public Document styleDocument(
Document document,
String stylesheet
) throws Exception {
// load the transformer using JAXP
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(
new StreamSource( stylesheet )
);
// now lets style the given document
DocumentSource source = new DocumentSource( document );
DocumentResult result = new DocumentResult();
transformer.transform( source, result );
// return the transformed document
Document transformedDoc = result.getDocument();
return transformedDoc;
}
7. 創(chuàng)建XML
一般創(chuàng)建XML是寫文件前的工作,這就像StringBuffer一樣容易。
public Document createDocument() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement(root);
Element author1 =
root
.addElement(author)
.addAttribute(name, James)
.addAttribute(location, UK)
.addText(James Strachan);
Element author2 =
root
.addElement(author)
.addAttribute(name, Bob)
.addAttribute(location, US)
.addText(Bob McWhirter);
return document;
}
8. 文件輸出
一個(gè)簡(jiǎn)單的輸出方法是將一個(gè)Document或任何的Node通過(guò)write方法輸出
FileWriter out = new FileWriter( foo.xml );
document.write(out);
如果你想改變輸出的格式,比如美化輸出或縮減格式,可以用XMLWriter類
public void write(Document document) throws IOException {
// 指定文件
XMLWriter writer = new XMLWriter(
new FileWriter( output.xml )
);
writer.write( document );
writer.close();
// 美化格式
OutputFormat format = OutputFormat.createPrettyPrint();
writer = new XMLWriter( System.out, format );
writer.write( document );
// 縮減格式
format = OutputFormat.createCompactFormat();
writer = new XMLWriter( System.out, format );
writer.write( document );
}
如何,DOM4J夠簡(jiǎn)單吧,當(dāng)然,還有一些復(fù)雜的應(yīng)用沒(méi)有提到,如ElementHandler等。如果你動(dòng)心了,那就一起來(lái)用DOM4J.
DOM4J官方網(wǎng)站:(我老連不上)
http://www.dom4j.orgDOM4J下載(SourceForge),最新版本為1.4
http://sourceforge.net/projects/dom4j參考資料:
DOM4J文檔
Java 中的 XML:文檔模型,第一部分:性能
http://www-900.ibm.com/developerWorks/cn/xml/x-injava/index.shtmlJava 中的 XML:Java 文檔模型的用法
http://www-900.ibm.com/developerWorks/cn/xml/x-injava2/index.shtmlJava XML API 漫談 by robbin
http://www.hibernate.org.cn:8000/137.html
Dom4j 使用簡(jiǎn)介
作者:冰云 icecloud(AT)sina.com
時(shí)間:2003.12.15
版權(quán)聲明:
本文由冰云完成,首發(fā)于CSDN,未經(jīng)許可,不得使用于任何商業(yè)用途。
文中代碼部分引用自DOM4J文檔。
歡迎轉(zhuǎn)載,但請(qǐng)保持文章及版權(quán)聲明完整。
如需聯(lián)絡(luò)請(qǐng)發(fā)郵件:icecloud(AT)sina.com
DOM4J是dom4j.org出品的一個(gè)開(kāi)源XML解析包,它的網(wǎng)站中這樣定義:
Dom4j is an easy to use, open source library for working with XML, XPath and XSLT on the Java platform using the Java Collections Framework and with full support for DOM, SAX and JAXP.
Dom4j是一個(gè)易用的、開(kāi)源的庫(kù),用于XML,XPath和XSLT。它應(yīng)用于Java平臺(tái),采用了Java集合框架并完全支持DOM,SAX和JAXP。
DOM4J使用起來(lái)非常簡(jiǎn)單。只要你了解基本的XML-DOM模型,就能使用。然而他自己帶的指南只有短短一頁(yè)(html),不過(guò)說(shuō)的到挺全。國(guó)內(nèi)的中文資料很少。因而俺寫這個(gè)短小的教程方便大家使用,這篇文章僅談及基本的用法,如需深入的使用,請(qǐng)……自己摸索或查找別的資料。
之前看過(guò)IBM developer社區(qū)的文章(參見(jiàn)附錄),提到一些XML解析包的性能比較,其中DOM4J的性能非常出色,在多項(xiàng)測(cè)試中名列前茅。(事實(shí)上DOM4J的官方文檔中也引用了這個(gè)比較)所以這次的項(xiàng)目中我采用了DOM4J作為XML解析工具。
在國(guó)內(nèi)比較流行的是使用JDOM作為解析器,兩者各擅其長(zhǎng),但DOM4J最大的特色是使用大量的接口,這也是它被認(rèn)為比JDOM靈活的主要原因。大師不是說(shuō)過(guò)么,“面向接口編程”。目前使用DOM4J的已經(jīng)越來(lái)越多。如果你善于使用JDOM,不妨繼續(xù)用下去,只看看本篇文章作為了解與比較,如果你正要采用一種解析器,不如就用DOM4J吧。
它的主要接口都在org.dom4j這個(gè)包里定義:
Attribute
Attribute定義了XML的屬性
Branch
Branch為能夠包含子節(jié)點(diǎn)的節(jié)點(diǎn)如XML元素(Element)和文檔(Docuemnts)定義了一個(gè)公共的行為,
CDATA
CDATA 定義了XML CDATA 區(qū)域
CharacterData
CharacterData是一個(gè)標(biāo)識(shí)借口,標(biāo)識(shí)基于字符的節(jié)點(diǎn)。如CDATA,Comment, Text.
Comment
Comment 定義了XML注釋的行為
Document
定義了XML文檔
DocumentType
DocumentType 定義XML DOCTYPE聲明
Element
Element定義XML 元素
ElementHandler
ElementHandler定義了 Element 對(duì)象的處理器
ElementPath
被 ElementHandler 使用,用于取得當(dāng)前正在處理的路徑層次信息
Entity
Entity定義 XML entity
Node
Node為所有的dom4j中XML節(jié)點(diǎn)定義了多態(tài)行為
NodeFilter
NodeFilter 定義了在dom4j節(jié)點(diǎn)中產(chǎn)生的一個(gè)濾鏡或謂詞的行為(predicate)
ProcessingInstruction
ProcessingInstruction 定義 XML 處理指令.
Text
Text 定義XML 文本節(jié)點(diǎn).
Visitor
Visitor 用于實(shí)現(xiàn)Visitor模式.
XPath
XPath 在分析一個(gè)字符串后會(huì)提供一個(gè)XPath 表達(dá)式
看名字大致就知道它們的涵義如何了。
要想弄懂這套接口,關(guān)鍵的是要明白接口的繼承關(guān)系:
interface java.lang.Cloneable
interface org.dom4j.Node
interface org.dom4j.Attribute
interface org.dom4j.Branch
interface org.dom4j.Document
interface org.dom4j.Element
interface org.dom4j.CharacterData
interface org.dom4j.CDATA
interface org.dom4j.Comment
interface org.dom4j.Text
interface org.dom4j.DocumentType
interface org.dom4j.Entity
interface org.dom4j.ProcessingInstruction
一目了然,很多事情都清楚了。大部分都是由Node繼承來(lái)的。知道這些關(guān)系,將來(lái)寫程序就不會(huì)出現(xiàn)ClassCastException了。
下面給出一些例子(部分摘自DOM4J自帶的文檔),簡(jiǎn)單說(shuō)一下如何使用。
1. 讀取并解析XML文檔:
讀寫XML文檔主要依賴于org.dom4j.io包,其中提供DOMReader和SAXReader兩類不同方式,而調(diào)用方式是一樣的。這就是依靠接口的好處。
// 從文件讀取XML,輸入文件名,返回XML文檔
public Document read(String fileName) throws MalformedURLException, DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(new File(fileName));
return document;
}
其中,reader的read方法是重載的,可以從InputStream, File, Url等多種不同的源來(lái)讀取。得到的Document對(duì)象就帶表了整個(gè)XML。
根據(jù)本人自己的經(jīng)驗(yàn),讀取的字符編碼是按照XML文件頭定義的編碼來(lái)轉(zhuǎn)換。如果遇到亂碼問(wèn)題,注意要把各處的編碼名稱保持一致即可。
2. 取得Root節(jié)點(diǎn)
讀取后的第二步,就是得到Root節(jié)點(diǎn)。熟悉XML的人都知道,一切XML分析都是從Root元素開(kāi)始的。
public Element getRootElement(Document doc){
return doc.getRootElement();
}
3. 遍歷XML樹(shù)
DOM4J提供至少3種遍歷節(jié)點(diǎn)的方法:
1) 枚舉(Iterator)
// 枚舉所有子節(jié)點(diǎn)
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
Element element = (Element) i.next();
// do something
}
// 枚舉名稱為foo的節(jié)點(diǎn)
for ( Iterator i = root.elementIterator(foo); i.hasNext();) {
Element foo = (Element) i.next();
// do something
}
// 枚舉屬性
for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
Attribute attribute = (Attribute) i.next();
// do something
}
2)遞歸
遞歸也可以采用Iterator作為枚舉手段,但文檔中提供了另外的做法
public void treeWalk() {
treeWalk(getRootElement());
}
public void treeWalk(Element element) {
for (int i = 0, size = element.nodeCount(); i < size; i++) {
Node node = element.node(i);
if (node instanceof Element) {
treeWalk((Element) node);
} else { // do something....
}
}
}
3) Visitor模式
最令人興奮的是DOM4J對(duì)Visitor的支持,這樣可以大大縮減代碼量,并且清楚易懂。了解設(shè)計(jì)模式的人都知道,Visitor是GOF設(shè)計(jì)模式之一。其主要原理就是兩種類互相保有對(duì)方的引用,并且一種作為Visitor去訪問(wèn)許多Visitable。我們來(lái)看DOM4J中的Visitor模式(快速文檔中沒(méi)有提供)
只需要自定一個(gè)類實(shí)現(xiàn)Visitor接口即可。
public class MyVisitor extends VisitorSupport {
public void visit(Element element){
System.out.println(element.getName());
}
public void visit(Attribute attr){
System.out.println(attr.getName());
}
}
調(diào)用: root.accept(new MyVisitor())
Visitor接口提供多種Visit()的重載,根據(jù)XML不同的對(duì)象,將采用不同的方式來(lái)訪問(wèn)。上面是給出的Element和Attribute的簡(jiǎn)單實(shí)現(xiàn),一般比較常用的就是這兩個(gè)。VisitorSupport是DOM4J提供的默認(rèn)適配器,Visitor接口的Default Adapter模式,這個(gè)模式給出了各種visit(*)的空實(shí)現(xiàn),以便簡(jiǎn)化代碼。
注意,這個(gè)Visitor是自動(dòng)遍歷所有子節(jié)點(diǎn)的。如果是root.accept(MyVisitor),將遍歷子節(jié)點(diǎn)。我第一次用的時(shí)候,認(rèn)為是需要自己遍歷,便在遞歸中調(diào)用Visitor,結(jié)果可想而知。
4. XPath支持
DOM4J對(duì)XPath有良好的支持,如訪問(wèn)一個(gè)節(jié)點(diǎn),可直接用XPath選擇。
public void bar(Document document) {
List list = document.selectNodes( //foo/bar );
Node node = document.selectSingleNode(//foo/bar/author);
String name = node.valueOf( @name );
}
例如,如果你想查找XHTML文檔中所有的超鏈接,下面的代碼可以實(shí)現(xiàn):
public void findLinks(Document document) throws DocumentException {
List list = document.selectNodes( //a/@href );
for (Iterator iter = list.iterator(); iter.hasNext(); ) {
Attribute attribute = (Attribute) iter.next();
String url = attribute.getValue();
}
}
5. 字符串與XML的轉(zhuǎn)換
有時(shí)候經(jīng)常要用到字符串轉(zhuǎn)換為XML或反之,
// XML轉(zhuǎn)字符串
Document document = ...;
String text = document.asXML();
// 字符串轉(zhuǎn)XML
String text = <person> <name>James</name> </person>;
Document document = DocumentHelper.parseText(text);
6 用XSLT轉(zhuǎn)換XML
public Document styleDocument(
Document document,
String stylesheet
) throws Exception {
// load the transformer using JAXP
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(
new StreamSource( stylesheet )
);
// now lets style the given document
DocumentSource source = new DocumentSource( document );
DocumentResult result = new DocumentResult();
transformer.transform( source, result );
// return the transformed document
Document transformedDoc = result.getDocument();
return transformedDoc;
}
7. 創(chuàng)建XML
一般創(chuàng)建XML是寫文件前的工作,這就像StringBuffer一樣容易。
public Document createDocument() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement(root);
Element author1 =
root
.addElement(author)
.addAttribute(name, James)
.addAttribute(location, UK)
.addText(James Strachan);
Element author2 =
root
.addElement(author)
.addAttribute(name, Bob)
.addAttribute(location, US)
.addText(Bob McWhirter);
return document;
}
8. 文件輸出
一個(gè)簡(jiǎn)單的輸出方法是將一個(gè)Document或任何的Node通過(guò)write方法輸出
FileWriter out = new FileWriter( foo.xml );
document.write(out);
如果你想改變輸出的格式,比如美化輸出或縮減格式,可以用XMLWriter類
public void write(Document document) throws IOException {
// 指定文件
XMLWriter writer = new XMLWriter(
new FileWriter( output.xml )
);
writer.write( document );
writer.close();
// 美化格式
OutputFormat format = OutputFormat.createPrettyPrint();
writer = new XMLWriter( System.out, format );
writer.write( document );
// 縮減格式
format = OutputFormat.createCompactFormat();
writer = new XMLWriter( System.out, format );
writer.write( document );
}
如何,DOM4J夠簡(jiǎn)單吧,當(dāng)然,還有一些復(fù)雜的應(yīng)用沒(méi)有提到,如ElementHandler等。如果你動(dòng)心了,那就一起來(lái)用DOM4J.
DOM4J官方網(wǎng)站:(我老連不上)
http://www.dom4j.org
DOM4J下載(SourceForge),最新版本為1.4
http://sourceforge.net/projects/dom4j
參考資料:
DOM4J文檔
Java 中的 XML:文檔模型,第一部分:性能
http://www-900.ibm.com/developerWorks/cn/xml/x-injava/index.shtml
Java 中的 XML:Java 文檔模型的用法
http://www-900.ibm.com/developerWorks/cn/xml/x-injava2/index.shtml
Java XML API 漫談 by robbin
http://www.hibernate.org.cn:8000/137.html