Attribute | Attribute定義了XML的屬性 |
Branch | Branch為能夠包含子節點的節點如XML元素(Element)和文檔(Docuemnts)定義了一個公共的行為, |
CDATA | CDATA 定義了XML CDATA 區域 |
| CharacterData是一個標識接口,標識基于字符的節點。如CDATA,Comment, Text. |
Comment | Comment 定義了XML注釋的行為 |
Document | 定義了XML文檔 |
DocumentType |
DocumentType 定義XML DOCTYPE聲明 |
Element | Element定義XML 元素 |
ElementHandler | ElementHandler定義了 Element 對象的處理器 |
ElementPath | 被 ElementHandler 使用,用于取得當前正在處理的路徑層次信息 |
Entity | Entity定義 XML entity |
Node | Node為所有的dom4j中XML節點定義了多態行為 |
| NodeFilter 定義了在dom4j節點中產生的一個濾鏡或謂詞的行為(predicate) |
ProcessingInstruction | ProcessingInstruction 定義 XML 處理指令. |
Text | Text 定義XML 文本節點. |
Visitor | Visitor 用于實現Visitor模式. |
XPath | XPath |

要想弄懂這套接口,關鍵的是要明白接口的繼承關系:
- interface java.lang.Cloneable
- 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
1. 讀取并解析XML文檔:
讀寫XML文檔主要依賴于org.dom4j.io包,其中提供DOMReader和SAXReader兩類不同方式,而調用方式是一樣的。這就是依靠接口的好處。
// 從文件讀取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等多種不同的源來讀取。得到的Document對象就帶表了整個XML。根據本人自己的經驗,讀取的字符編碼是按照XML文件頭定義的編碼來轉換。如果遇到亂碼問題,注意要把各處的編碼名稱保持一致即可。
2. 取得Root節點
讀取后的第二步,就是得到Root節點。熟悉XML的人都知道,一切XML分析都是從Root元素開始的。
public Element getRootElement(Document doc){ return doc.getRootElement(); } |
3. 遍歷XML樹
DOM4J提供至少3種遍歷節點的方法:
1) 枚舉(Iterator)
// 枚舉所有子節點 for ( Iterator i = root.elementIterator(); i.hasNext(); ) { Element element = (Element) i.next(); // do something } // 枚舉名稱為foo的節點 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對Visitor的支持,這樣可以大大縮減代碼量,并且清楚易懂。了解設計模式的人都知道,Visitor是GOF設計模式之一。其主要原理就是兩種類互相保有對方的引用,并且一種作為Visitor去訪問許多Visitable。我們來看DOM4J中的Visitor模式(快速文檔中沒有提供)
只需要自定一個類實現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()); } } 調用: root.accept(new MyVisitor()) |
Visitor接口提供多種Visit()的重載,根據XML不同的對象,將采用不同的方式來訪問。上面是給出的Element和Attribute的簡單實現,一般比較常用的就是這兩個。VisitorSupport是DOM4J提供的默認適配器,Visitor接口的Default Adapter模式,這個模式給出了各種visit(*)的空實現,以便簡化代碼。
注意,這個Visitor是自動遍歷所有子節點的。如果是root.accept(MyVisitor),將遍歷子節點。我第一次用的時候,認為是需要自己遍歷,便在遞歸中調用Visitor,結果可想而知。
4. XPath支持
DOM4J對XPath有良好的支持,如訪問一個節點,可直接用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文檔中所有的超鏈接,下面的代碼可以實現:
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的轉換
有時候經常要用到字符串轉換為XML或反之,
// XML轉字符串 Document document = ...; String text = document.asXML(); // 字符串轉XML String text = <person> <name>James</name> </person>; Document document = DocumentHelper.parseText(text); |
6 用XSLT轉換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. 創建XML
一般創建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. 文件輸出
一個簡單的輸出方法是將一個Document或任何的Node通過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 ); } |
5.使用ElementHandler
XmlHandler.java
import java.io.File;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
import org.dom4j.io.SAXReader;
public class XmlHandler {
public static void main(String[] args) {
SAXReader saxReader = new SAXReader();
File file = new File("students.xml");
try {
// 添加一個ElementHandler實例。
saxReader.addHandler("/students/student", new StudentHandler());
saxReader.read(file);
} catch (DocumentException e) {
System.out.println(e.getMessage());
}
}
/**
* 定義StudentHandler處理器類,對<student>元素進行處理。
*/
private static class StudentHandler implements ElementHandler {
public void .Start(ElementPath path) {
Element elt = path.getCurrent();
System.out.println("Found student: " + elt.attribut.ue("sn"));
// 添加對子元素<name>的處理器。
path.addHandler("name", new NameHandler());
}
public void .End(ElementPath path) {
// 移除對子元素<name>的處理器。
path.removeHandler("name");
}
}
/**
* 定義NameHandler處理器類,對<student>的<name>子元素進行處理。
*/
private static class NameHandler implements ElementHandler {
public void .Start(ElementPath path) {
System.out.println("path : " + path.getPath());
}
public void .End(ElementPath path) {
Element elt = path.getCurrent();
// 輸出<name>元素的名字和它的文本內容。
System.out.println(elt.getName() + " : " + elt.getText());
}
}
}