dom4j 之 XML 解析
1:dom4j 簡介:
解析XML 文檔的開放源代碼XML 框架,支持 XML,XPath,XSLT, 出現前景是早期的 dom4j 分離出來後創建的,相對比 dom4j 靈活,也使用SAX 解析器來分析文檔。
dom4j API 介紹
/**
*dom4j 創建 XML 文件
*/
public static void main(String[] args) {
// 創建根元素節點 然後創建文檔對象
Element elRoot = DocumentHelper.createElement("student");
Document doc = DocumentHelper.createDocument(elRoot);
// 添加屬性 先添加根節點的屬性
elRoot.addAttribute("sn", "1");
//添加子元素和元素內容
Element elName = elRoot.addElement("name");
Element elAge = elRoot.addElement("age");
elName.setText("郭新傑");
elAge.setText("28");
//輸出文檔 到文件
try {
OutputFormat format = OutputFormat.createCompactFormat();
format.setEncoding("GB2312");
format.setIndent(" ");
//XMLWriter writer = new XMLWriter(new FileOutputStream("stu.xml"));輸出到文件
XMLWriter writer = new XMLWriter(format);// 規範化輸出
writer.write(doc);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
xml 例子爲:
<?xml version="1.0" encoding="GB2312"?>
<?xml-stylesheet type="text/xsl" href="student.xsl"?>
<students>
<student sn="1">
<name>張三</name>
<age>12</age>
</student>
<student sn="2">
<name>李四</name>
<age>13</age>
</student>
<student sn="3">
<name>王五</name>
<age>14</age>
</student>
<student sn="4">
<name>趙六</name>
<age>15</age>
</student>
</students>
構建 DOM 樹 -- xml文件的 dom4j 解析
dom4j 在 包中提供了兩個類,DOMReader :從一個現有的 W3C DOM 樹構建 dom4j 樹
SAXReader : 使用 SAX 解析器,從不同的輸入源來構造 dom4j 樹
以SAXReader 爲例來創建文檔對象
SAXReader sax = new SAXReader();
接上面代碼爲:
SAXReader sax = new SAXReader();
File file = new File("test.xml");
try {
Document d = sax.read(file);
// 訪問根元素
Element root = d.getRootElement();
// 得到某個元素的所有子元素
List list = root.elements();
// 利用 XPath 表達式,需要引進 包 jaxen 的支持
list = root.selectNodes("//name"); //獲取 所有 <name> 的元素
list = root.selectNodes("//student[@sn='1']"); //獲取 sn 的值=1的<student> 元素
// XPath 表達式結束 --------------------------------------
System.out.println("\n"+list.size());
for(int m = 0;m<list.size();m++){
Element name =(Element) list.get(m);
System.out.println("這裏是 sn 的值 -- "+name.attributeValue("sn"));// 這裏是獲取元素的指定屬性 比如:sn
//System.out.println("00 -- "+name.elementText("name"));// 獲取name 的值 這裏使用SAXReader 來獲取
System.out.println("00 -- "+name.getStringValue());// 獲取name 的值 這裏使用 XPath 表達式來獲取
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// -------------------------------------------------以 DOMReader 來構造對象
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = df.newDocumentBuilder();
File f = new File("test.xml");
org.w3c.dom.Document doc1 = db.parse(f);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
好了 基礎回顧結束,下面開始講解 dom4j 的訪問者模式 和 基於事件的處理
2 : dom4j 訪問者模式
實際應用中,我們往往需要遍歷整個XML 文檔,根據不同類型的節點進行不同的操作,這個時候可以考慮下訪問者模式(VIsitor),通常用於處理對象樹結構,樹中的每個節點對象都可以接受一個訪問者對象,
節點對象向訪問者對象傳遞本身。訪問者對象反過來調用節點對象的操作。
dom4j 包中 有個 Visitor 接口,針對不同類型節點,定義了多個重載的 visit() 方法 如:訪問元素方法爲 void visit(Element node) 訪問元素屬性方法爲: void visit(Attribute node)
我們需要實現 Visitor 接口 然後在 node 中定義了一個 accept(Visitor v)
例子:
public class Dom4jVisitor {
/**
* dom4j 訪問者模式
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SAXReader read = new SAXReader();
File f = new File("test.xml");
try{
Document doc = read.read(f);
doc.accept(new MyVisitor());
}catch(Exception e){
e.printStackTrace();
}
}
}
package com.tide.servlet;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.dom4j.ProcessingInstruction;
import org.dom4j.VisitorSupport;
public class MyVisitor extends VisitorSupport {
/**
* 對於屬性節點,打印出屬性的名稱和值
*/
public void visit(Attribute node){
System.out.println("attribute: "+node.getName()+" == "+node.getValue());
}
/**
* 對於處理指令節點,打印出處理指令目標和數據
*/
public void visit(ProcessingInstruction node){
System.out.println("處理指令 :"+node.getTarget()+" -- "+node.getText());
}
/**
* 對於元素節點,判斷是否只包含文本內容,如果是 打印出元素名稱和內容
* 如果不是,只打印元素的名稱
*/
public void visit(Element node){
if(node.isTextOnly()){
System.out.println("element: "+node.getName()+" == "+node.getText());
}
}
}
打印後的內容爲:
處理指令 :xml-stylesheet -- type="text/xsl" href="student.xsl" attribute: sn == 1 element: name == 張三 element: age == 12 attribute: sn == 2 element: name == 李四 element: age == 13 attribute: sn == 3 element: name == 王五 element: age == 14 attribute: sn == 4 element: name == 趙六 element: age == 15
3:dom4j 基於對事件的處理
dom4j 支持對文檔的基於事件的處理,尤其是對於較大的文檔,可以利用 dom4j 提供的基於事件的處理模型,在解析過程中進行處理,而不必等到整個文檔解析完畢。
SAXReader 定義了 addHandler() 方法,用於添加一個 ElementHandler 實例
public void addHandler(String path,ElementHandler handler) 當解析到參數 path 指定的路徑時,將調用參數 handler 指定的處理器,針對不同的節點路徑,可以添加多個ElementHandler實例。
ElementHandler 接口的方法主要有:
void onStart(ElementPath path) // 解析遇到元素的開始標籤時被調用
void onEnd(ElementPath path) // 解析遇到元素的結束標籤時被調用
ElementPath 接口主要方法:
void addHandler(String path,ElementHandler handler) 和 SAXReader 的 addHandler() 方法大致相同
void removeHandler(String path)
String getPath() //獲取當前節點路徑
Element getCurrent() //獲取當前元素
例子:xml 文件還是上面的xml 最大的好處是不必要便利文檔所有內容就可以對內容進行處理
public class Test4 {
/**
* dom4j 基於事件的處理 ElementHandler
*/
public static void main(String[] args) {
SAXReader read = new SAXReader();
File f = new File("test.xml");
read.addHandler("/students/student", (ElementHandler) new StudentHandler());
try{
read.read(f);
}catch(Exception e){
e.printStackTrace();
}
}
}
package com.tide.servlet; import org.dom4j.Element; import org.dom4j.ElementHandler; import org.dom4j.ElementPath; /** * 定義 StudentHandler 處理器類, 對 <student> 元素進行處理 * @author Administrator * */ public class StudentHandler implements ElementHandler{ @Override public void onStart(ElementPath path) { Element ele = path.getCurrent(); System.out.println("Fount student : "+ele.attributeValue("sn")); //添加對子元素 name 的處理器 path.addHandler("name", new Namehandler()); System.out.println("添加對子元素 name 的處理器"); } @Override public void onEnd(ElementPath path) { // 移除對子元素 name 的處理器 path.removeHandler("name"); System.out.println("移除對子元素 name 的處理器"); } }
package com.tide.servlet;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
public class Namehandler implements ElementHandler {
@Override
public void onEnd(ElementPath path) {
Element ele = path.getCurrent();
//輸出 <name> 元素的名稱和文本內容
System.out.println("name :"+ele.getName()+" == "+ele.getText());
}
@Override
public void onStart(ElementPath path) {
System.out.println("path : "+path.getPath());
}
}
最後的輸出內容爲:
Fount student : 1 添加對子元素 name 的處理器 path : /students/student/name name :name == 張三 移除對子元素 name 的處理器 Fount student : 2 添加對子元素 name 的處理器 path : /students/student/name name :name == 李四 移除對子元素 name 的處理器 Fount student : 3 添加對子元素 name 的處理器 path : /students/student/name name :name == 王五 移除對子元素 name 的處理器 Fount student : 4 添加對子元素 name 的處理器 path : /students/student/name name :name == 趙六 移除對子元素 name 的處理器