dom4j处理超大XML


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()方法保存改。
下面是示例代码:


Java代码
  1. SAXReader reader = new SAXReader();  
  2. reader.addHandler( "/ROWSET/ROW",  
  3.     new ElementHandler() {  
  4.         public void onStart(ElementPath path) {  
  5.             // do nothing here...      
  6.         }  
  7.         public void onEnd(ElementPath path) {  
  8.             // process a ROW element  
  9.             Element row = path.getCurrent();  
  10.             Element rowSet = row.getParent();  
  11.             Document document = row.getDocument();  
  12.             ...  
  13.             // prune the tree  
  14.             row.detach();  
  15.         }  
  16.     }  
  17. );  
  18.    
  19. 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()
动手一试,问题搞定,看来牛皮没白吹。下面是示例代码:


Java代码
  1. /** 
  2.   * 数据写入xml文件 
  3.   * @param filePath 目标xml文件的存放路径 
  4.   * @return 
  5.   */  
  6. public boolean writeXML(String filePath){  
  7.   XMLWriter out;  
  8.   try {  
  9.     
  10.    /* 
  11.     * 创建XMLWriter对象,设置XML编码,解决中文问题。 
  12.     */  
  13.    OutputFormat outputFormat = OutputFormat.createPrettyPrint();  
  14.    outputFormat.setEncoding("GBK");  
  15.    out = new XMLWriter(new FileWriter(filePath),outputFormat);  
  16.     
  17.     
  18.    out.startDocument();  
  19.    Element rootElement = DocumentHelper.createElement("mans");  
  20.    out.writeOpen(rootElement);  
  21.     
  22.    /* 
  23.     * 向mans节点写入子节点 
  24.     */  
  25.    for(int i=0 ; i<1000000 ; i++){  
  26.     Element man = createManElement(new Long(i), "shuhang"+i);//用于创建节点的方法  
  27.     out.write(man);  
  28.     System.out.println(" the loop index is : " + i);  
  29.    }  
  30.     
  31.    out.writeClose(rootElement);  
  32.    out.endDocument();  
  33.     
  34.    out.close();  
  35.    return true;  
  36.   } catch (IOException e) {  
  37.    e.printStackTrace();  
  38.    return false;  
  39.   } catch (SAXException e) {  
  40.    e.printStackTrace();  
  41.    return false;  
  42.   }  
  43. }  
/**

  * 数据写入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的注册事件处理器应该用的是 模板方法,通过钩子将用户的操作加入到模板中去。何不自己写一个事件处理器来完成我们自己的定制操作,代码如下:

Java代码
  1. public class ManElementHandler implements ElementHandler {  
  2. public String mdbName;  
  3. ­  
  4. public ManElementHandler(){  
  5.     
  6. }  
  7. ­  
  8. public ManElementHandler(String mdbName){  
  9.   this.mdbName = mdbName;  
  10. }  
  11. ­  
  12. public boolean saveMan(Element element, String mdbName){  
  13.   return true;  
  14. }  
  15. ­  
  16. public void onEnd(ElementPath arg0) {  
  17.          Element row = arg0.getCurrent();  
  18.          Element rowSet = row.getParent();  
  19.          Document document = row.getDocument();  
  20.          Element root = document.getRootElement();  
  21.   Iterator it = root.elementIterator();  
  22.   while(it.hasNext()){  
  23.    Element element = (Element)it.next();  
  24.    System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name"));  
  25.    saveMan(element, this.mdbName);  
  26.   }  
  27.          row.detach();  
  28. }  
  29. public void onStart(ElementPath path) {  
  30.     
  31. }  
  32. }  
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未发生内存溢出。


Java代码
  1. //*****************************************************************************************************************  
  2. package com;  
  3. import java.sql.Connection;  
  4. import java.sql.DriverManager;  
  5. /**  
  6. * 获取Access数据库的连接  
  7. @author 佛山无影脚  
  8. @version 1.0  
  9. * Jul 72008  4:35:49 PM  
  10. */  
  11. public class AccessMDBUtil {  
  12. public static Connection connectMdb(String mdbName) {  
  13.   if(mdbName == null || mdbName.equals("")){  
  14.    return null;  
  15.   }  
  16.   try {  
  17.    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");  
  18.    String dburl ="jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ="+mdbName;  
  19.    Connection conn=DriverManager.getConnection(dburl);  
  20.    return conn;  
  21.   } catch (Exception e) {  
  22.    e.printStackTrace();  
  23.    return null;  
  24.   }  
  25. }  
  26. }  
  27. //*******************************************************************************************************************  
  28. //*******************************************************************************************************************  
  29. package com;  
  30. import java.sql.Connection;  
  31. import java.sql.ResultSet;  
  32. import java.sql.SQLException;  
  33. import java.sql.Statement;  
  34. import java.util.Iterator;  
  35. import org.dom4j.Document;  
  36. import org.dom4j.Element;  
  37. import org.dom4j.ElementHandler;  
  38. import org.dom4j.ElementPath;  
  39. /**  
  40. * 定制的事件处理器  
  41. @author 佛山无影脚  
  42. @version 1.0  
  43. * Jul 72008  4:35:49 PM  
  44. */  
  45. public class ManElementHandler implements ElementHandler {  
  46. public String mdbName;//数据库名称 含路径  
  47. ­  
  48. public ManElementHandler(){  
  49.     
  50. }  
  51. ­  
  52. public ManElementHandler(String mdbName){  
  53.   this.mdbName = mdbName;  
  54. }  
  55. ­  
  56. /** 
  57.   *将Element节点数据保存到数据库 
  58.   *@param element 遍历XML文档时的当前节点 
  59.   *@param mdbName 数据库名称 含路径 
  60.   *@return 
  61.   */  
  62. public boolean saveMan(Element element, String mdbName){  
  63.   System.out.println(" the method saveMan in ManElementHandler is execute!");  
  64.   Statement stmt = null;  
  65.   ResultSet rs = null;  
  66.   Connection conn = null;  
  67.   try {  
  68.    conn= AccessMDBUtil.connectMdb(mdbName);  
  69.    stmt=conn.createStatement();  
  70.    String sql = "insert into mans(id,name) values(" + element.elementText("id") + ",'" + element.elementText("name") + "')";  
  71.    stmt.executeUpdate(sql);  
  72.     
  73.   } catch (Exception e) {  
  74.    e.printStackTrace();  
  75.    return false;  
  76.   } finally {  
  77.    if(rs != null) {  
  78.     try {  
  79.      rs.close();  
  80.     } catch (SQLException e) {  
  81.      // TODO Auto-generated catch block  
  82.      e.printStackTrace();  
  83.     }  
  84.    }  
  85.    if(stmt != null) {  
  86.     try {  
  87.      stmt.close();  
  88.     } catch (SQLException e) {  
  89.      // TODO Auto-generated catch block  
  90.      e.printStackTrace();  
  91.     }  
  92.    }  
  93.    if(conn != null) {  
  94.     try {  
  95.      conn.close();  
  96.     } catch (SQLException e) {  
  97.      // TODO Auto-generated catch block  
  98.      e.printStackTrace();  
  99.     }  
  100.    }  
  101.     
  102.   }  
  103.     
  104.   return true;  
  105. }  
  106. ­  
  107. public void onEnd(ElementPath arg0) {  
  108.          Element row = arg0.getCurrent();  
  109.          Element rowSet = row.getParent();  
  110.          Document document = row.getDocument();  
  111.          Element root = document.getRootElement();  
  112.   Iterator it = root.elementIterator();  
  113.   while(it.hasNext()){  
  114.    Element element = (Element)it.next();  
  115.    System.out.println(" id : " + element.elementText("id") + " name : " + element.elementText("name"));  
  116.    saveMan(element, this.mdbName);  
  117.   }  
  118.           row.detach();  
  119. }  
  120. public void onStart(ElementPath path) {  
  121.     
  122. }  
  123. }  
  124. //*************************************************************************************************************************  
  125. //*************************************************************************************************************************  
  126. package com;  
  127. import java.io.File;  
  128. import java.io.FileWriter;  
  129. import java.io.IOException;  
  130. import org.dom4j.Document;  
  131. import org.dom4j.DocumentException;  
  132. import org.dom4j.DocumentHelper;  
  133. import org.dom4j.Element;  
  134. import org.dom4j.io.OutputFormat;  
  135. import org.dom4j.io.SAXReader;  
  136. import org.dom4j.io.XMLWriter;  
  137. import org.xml.sax.SAXException;  
  138. import org.xml.sax.XMLReader;  
  139. /**  
  140. * 测试  
  141. @author 佛山无影脚  
  142. @version 1.0  
  143. * Jul 72008  4:35:49 PM  
  144. */  
  145. public class ManTest {  
  146. /** 
  147.   * 创建man节点 
  148.   * <man><id>1</id><name>佛山无影脚</name></man> 
  149.   * @param id 
  150.   * @param name 
  151.   * @return 
  152.   */  
  153. public Element createManElement(Long id,String name){  
  154.   Element manElement = DocumentHelper.createElement("man");  
  155.   manElement.addElement("id").addText(id.toString());  
  156.   manElement.addElement("name").addText(name);  
  157.   return manElement;  
  158. }  
  159. ­  
  160. /** 
  161.   * 数据写入xml文件 
  162.   * @param filePath 目标xml文件的存放路径 
  163.   * @return 
  164.   */  
  165. public boolean writeXML(String filePath){  
  166.   XMLWriter out;  
  167.   try {  
  168.     
  169.    /* 
  170.     * 创建XMLWriter对象,设置XML编码,解决中文问题。 
  171.     */  
  172.    OutputFormat outputFormat = OutputFormat.createPrettyPrint();  
  173.    outputFormat.setEncoding("GBK");  
  174.    out = new XMLWriter(new FileWriter(filePath),outputFormat);  
  175.     
  176.     
  177.    out.startDocument();  
  178.    Element rootElement = DocumentHelper.createElement("mans");  
  179.    out.writeOpen(rootElement);  
  180.     
  181.    /* 
  182.     * 向mans节点写入子节点 
  183.     */  
  184.    for(int i=0 ; i<1000000 ; i++){  
  185.     Element man = this.createManElement(new Long(i), "shuhang"+i);  
  186.     out.write(man);  
  187.     System.out.println(" the loop index is : " + i);  
  188.    }  
  189.     
  190.    out.writeClose(rootElement);  
  191.    out.endDocument();  
  192.     
  193.    out.close();  
  194.    return true;  
  195.   } catch (IOException e) {  
  196.    e.printStackTrace();  
  197.    return false;  
  198.   } catch (SAXException e) {  
  199.    e.printStackTrace();  
  200.    return false;  
  201.   }  
  202. }  
  203. ­  
  204. /** 
  205.   * 从xml文件中读取数据,并将数据写入Access数据 
  206.   * @param filePath xml文件的存放路径 
  207.   * @return 
  208.   */  
  209. public boolean readXML(String filePath){  
  210.     
  211.   ManElementHandler manElementHandler = new ManElementHandler("F:\\dom4j\\xmlTest.mdb");  
  212.   SAXReader reader = new SAXReader();  
  213.   reader.addHandler( "/mans/man", manElementHandler);  
  214.   Document document = null;  
  215.      try {  
  216.       File file = new File(filePath);  
  217.    document = reader.read(file);  
  218.   } catch (DocumentException e) {  
  219.    e.printStackTrace();  
  220.    return false;  
  221.   }  
  222.   return true;  
  223. }  
  224. ­  
  225. ­  
  226. public static void main(String[] args){  
  227.   XMLReader reader = null;  
  228.   long startTime = System.currentTimeMillis();  
  229.   ManTest mantest = new ManTest();  
  230.     
  231.   mantest.writeXML("f:\\dom4j\\mans.xml");  
  232.   mantest.readXML("f:\\dom4j\\mans.xml");  
  233.     
  234.   long endTime = System.currentTimeMillis();  
  235.   System.out.println(" is end! the millis is : " + (endTime - startTime));  
  236.     
  237. }  
  238. }  

你可能感兴趣的:(dom4j)