dom4j处理超大XML

 英文原文 : http://dom4j.sourceforge.net/dom4j-1.6.1/faq.html#large-doc

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值