dom4j提供了基於事件的模型來操作xml文檔。利用該模型開發人員可以一部分、一部分的處理XML文檔,而不需要將整個XML文檔都加載到內存中。例如:假想你要處理一個非常大的XML文檔,它可能是由數據庫的某張數據表而來的。如下所示:
<ROWSET>
<ROW ID="1">
...
</ROW>
<ROW ID="2">
...
</ROW>
...
<ROW ID="N">
...
</ROW>
</ROWSET>
我們可以在某一時間只處理一個ROW節點,而不必立刻將文檔的所有內容加載到內存中。dom4j提供一個基於事件的模型來實現它。我們可以註冊一個事件處理器來處理一個或多個路徑表達式。事件處理器會在註冊路徑的開始和結束時被調用執行。當註冊路徑的開始標籤找到時執行事件處理器的 onStart()方法,當註冊路徑的結束標籤被找到時執行事件處理器的onEnd()方法。
onStart()和onEnd()方法傳遞一個ElementPath實例參數,這個實例既爲根據註冊路徑遍歷xml文檔時的當前節點(Element)。如果想對遍歷的當前節點進行操作,可以在onEnd()方法中對當前節點調用detach()方法保存改。
下面是示例代碼:
- SAXReader reader = new SAXReader();
- reader.addHandler( "/ROWSET/ROW",
- new ElementHandler() {
- public void onStart(ElementPath path) {
- // do nothing here...
- }
- public void onEnd(ElementPath path) {
- // process a ROW element
- Element row = path.getCurrent();
- Element rowSet = row.getParent();
- Document document = row.getDocument();
- ...
- // prune the tree
- row.detach();
- }
- }
- );
- Document document = reader.read(url);
SAXReader reader = new SAXReader();
reader.addHandler( "/ROWSET/ROW",
new ElementHandler() {
public void onStart(ElementPath path) {
// do nothing here...
}
public void onEnd(ElementPath path) {
// process a ROW element
Element row = path.getCurrent();
Element rowSet = row.getParent();
Document document = row.getDocument();
...
// prune the tree
row.detach();
}
}
);
Document document = reader.read(url);
上面的辦法解決了讀的問題可是寫的問題還沒有解決。我命由我不由天(吹牛皮),暢遊dom4j的doc文檔找到如下幾個方法
startDocument()
writeOpen();
writeClose();
endDocument()
動手一試,問題搞定,看來牛皮沒白吹。下面是示例代碼:
- /**
- * 數據寫入xml文件
- * @param filePath 目標xml文件的存放路徑
- * @return
- */
- public boolean writeXML(String filePath){
- XMLWriter out;
- try {
- /*
- * 創建XMLWriter對象,設置XML編碼,解決中文問題。
- */
- OutputFormat outputFormat = OutputFormat.createPrettyPrint();
- outputFormat.setEncoding("GBK");
- out = new XMLWriter(new FileWriter(filePath),outputFormat);
- out.startDocument();
- Element rootElement = DocumentHelper.createElement("mans");
- out.writeOpen(rootElement);
- /*
- * 向mans節點寫入子節點
- */
- for(int i=0 ; i<1000000 ; i++){
- Element man = createManElement(new Long(i), "shuhang"+i);//用於創建節點的方法
- out.write(man);
- System.out.println(" the loop index is : " + i);
- }
- out.writeClose(rootElement);
- out.endDocument();
- out.close();
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- } catch (SAXException e) {
- e.printStackTrace();
- return false;
- }
- }
/**
* 數據寫入xml文件
* @param filePath 目標xml文件的存放路徑
* @return
*/
public boolean writeXML(String filePath){
XMLWriter out;
try {
/*
* 創建XMLWriter對象,設置XML編碼,解決中文問題。
*/
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("GBK");
out = new XMLWriter(new FileWriter(filePath),outputFormat);
out.startDocument();
Element rootElement = DocumentHelper.createElement("mans");
out.writeOpen(rootElement);
/*
* 向mans節點寫入子節點
*/
for(int i=0 ; i<1000000 ; i++){
Element man = createManElement(new Long(i), "shuhang"+i);//用於創建節點的方法
out.write(man);
System.out.println(" the loop index is : " + i);
}
out.writeClose(rootElement);
out.endDocument();
out.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (SAXException e) {
e.printStackTrace();
return false;
}
}
新問題出現。對於讀取數據的方法,在onEnd()方法中只是進行對Element的簡單操作而已,若要對Element進行復雜的處理怎麼辦,如將 Element節點的數據寫入數據庫,無法在onEnd()方法中加入過多的代碼,因爲無法通過編譯。仔細想了一下dom4j的註冊事件處理器應該用的是模板方法,通過鉤子將用戶的操作加入到模板中去。何不自己寫一個事件處理器來完成我們自己的定製操作,代碼如下:
- public class ManElementHandler implements ElementHandler {
- public String mdbName;
-
- public ManElementHandler(){
- }
-
- public ManElementHandler(String mdbName){
- this.mdbName = mdbName;
- }
-
- public boolean saveMan(Element element, String mdbName){
- return true;
- }
-
- public void onEnd(ElementPath arg0) {
- Element row = arg0.getCurrent();
- Element rowSet = row.getParent();
- Document document = row.getDocument();
- Element root = document.getRootElement();
- Iterator it = root.elementIterator();
- while(it.hasNext()){
- Element element = (Element)it.next();
- System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name"));
- saveMan(element, this.mdbName);
- }
- row.detach();
- }
- public void onStart(ElementPath path) {
- }
- }
public class ManElementHandler implements ElementHandler {
public String mdbName;
public ManElementHandler(){
}
public ManElementHandler(String mdbName){
this.mdbName = mdbName;
}
public boolean saveMan(Element element, String mdbName){
return true;
}
public void onEnd(ElementPath arg0) {
Element row = arg0.getCurrent();
Element rowSet = row.getParent();
Document document = row.getDocument();
Element root = document.getRootElement();
Iterator it = root.elementIterator();
while(it.hasNext()){
Element element = (Element)it.next();
System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name"));
saveMan(element, this.mdbName);
}
row.detach();
}
public void onStart(ElementPath path) {
}
}
下面給出完整的實例代碼。該實例首先創建一個xml文檔,然後讀取xml文檔中的數據並將數據寫入Access數據庫中。測試時使用的文件大小爲125M未發生內存溢出。
- //*****************************************************************************************************************
- package com;
- import java.sql.Connection;
- import java.sql.DriverManager;
- /**
- * 獲取Access數據庫的連接
- * @author 佛山無影腳
- * @version 1.0
- * Jul 7, 2008 4:35:49 PM
- */
- public class AccessMDBUtil {
- public static Connection connectMdb(String mdbName) {
- if(mdbName == null || mdbName.equals("")){
- return null;
- }
- try {
- Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
- String dburl ="jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ="+mdbName;
- Connection conn=DriverManager.getConnection(dburl);
- return conn;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- }
- //*******************************************************************************************************************
- //*******************************************************************************************************************
- package com;
- import java.sql.Connection;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- import java.util.Iterator;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.ElementHandler;
- import org.dom4j.ElementPath;
- /**
- * 定製的事件處理器
- * @author 佛山無影腳
- * @version 1.0
- * Jul 7, 2008 4:35:49 PM
- */
- public class ManElementHandler implements ElementHandler {
- public String mdbName;//數據庫名稱 含路徑
-
- public ManElementHandler(){
- }
-
- public ManElementHandler(String mdbName){
- this.mdbName = mdbName;
- }
-
- /**
- *將Element節點數據保存到數據庫
- *@param element 遍歷XML文檔時的當前節點
- *@param mdbName 數據庫名稱 含路徑
- *@return
- */
- public boolean saveMan(Element element, String mdbName){
- System.out.println(" the method saveMan in ManElementHandler is execute!");
- Statement stmt = null;
- ResultSet rs = null;
- Connection conn = null;
- try {
- conn= AccessMDBUtil.connectMdb(mdbName);
- stmt=conn.createStatement();
- String sql = "insert into mans(id,name) values(" + element.elementText("id") + ",'" + element.elementText("name") + "')";
- stmt.executeUpdate(sql);
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- } finally {
- if(rs != null) {
- try {
- rs.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if(stmt != null) {
- try {
- stmt.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if(conn != null) {
- try {
- conn.close();
- } catch (SQLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- return true;
- }
-
- public void onEnd(ElementPath arg0) {
- Element row = arg0.getCurrent();
- Element rowSet = row.getParent();
- Document document = row.getDocument();
- Element root = document.getRootElement();
- Iterator it = root.elementIterator();
- while(it.hasNext()){
- Element element = (Element)it.next();
- System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name"));
- saveMan(element, this.mdbName);
- }
- row.detach();
- }
- public void onStart(ElementPath path) {
- }
- }
- //*************************************************************************************************************************
- //*************************************************************************************************************************
- package com;
- import java.io.File;
- import java.io.FileWriter;
- import java.io.IOException;
- import org.dom4j.Document;
- import org.dom4j.DocumentException;
- import org.dom4j.DocumentHelper;
- import org.dom4j.Element;
- import org.dom4j.io.OutputFormat;
- import org.dom4j.io.SAXReader;
- import org.dom4j.io.XMLWriter;
- import org.xml.sax.SAXException;
- import org.xml.sax.XMLReader;
- /**
- * 測試
- * @author 佛山無影腳
- * @version 1.0
- * Jul 7, 2008 4:35:49 PM
- */
- public class ManTest {
- /**
- * 創建man節點
- * <man><id>1</id><name>佛山無影腳</name></man>
- * @param id
- * @param name
- * @return
- */
- public Element createManElement(Long id,String name){
- Element manElement = DocumentHelper.createElement("man");
- manElement.addElement("id").addText(id.toString());
- manElement.addElement("name").addText(name);
- return manElement;
- }
-
- /**
- * 數據寫入xml文件
- * @param filePath 目標xml文件的存放路徑
- * @return
- */
- public boolean writeXML(String filePath){
- XMLWriter out;
- try {
- /*
- * 創建XMLWriter對象,設置XML編碼,解決中文問題。
- */
- OutputFormat outputFormat = OutputFormat.createPrettyPrint();
- outputFormat.setEncoding("GBK");
- out = new XMLWriter(new FileWriter(filePath),outputFormat);
- out.startDocument();
- Element rootElement = DocumentHelper.createElement("mans");
- out.writeOpen(rootElement);
- /*
- * 向mans節點寫入子節點
- */
- for(int i=0 ; i<1000000 ; i++){
- Element man = this.createManElement(new Long(i), "shuhang"+i);
- out.write(man);
- System.out.println(" the loop index is : " + i);
- }
- out.writeClose(rootElement);
- out.endDocument();
- out.close();
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- } catch (SAXException e) {
- e.printStackTrace();
- return false;
- }
- }
-
- /**
- * 從xml文件中讀取數據,並將數據寫入Access數據
- * @param filePath xml文件的存放路徑
- * @return
- */
- public boolean readXML(String filePath){
- ManElementHandler manElementHandler = new ManElementHandler("F:\\dom4j\\xmlTest.mdb");
- SAXReader reader = new SAXReader();
- reader.addHandler( "/mans/man", manElementHandler);
- Document document = null;
- try {
- File file = new File(filePath);
- document = reader.read(file);
- } catch (DocumentException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
-
- public static void main(String[] args){
- XMLReader reader = null;
- long startTime = System.currentTimeMillis();
- ManTest mantest = new ManTest();
- mantest.writeXML("f:\\dom4j\\mans.xml");
- mantest.readXML("f:\\dom4j\\mans.xml");
- long endTime = System.currentTimeMillis();
- System.out.println(" is end! the millis is : " + (endTime - startTime));
- }
- }