dom4j处理超大XML

转自:http://extjs2.javaeye.com/blog/852456

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. SAXReaderreader=newSAXReader();
  2. reader.addHandler("/ROWSET/ROW",
  3. newElementHandler(){
  4. publicvoidonStart(ElementPathpath){
  5. //donothinghere...
  6. }
  7. publicvoidonEnd(ElementPathpath){
  8. //processaROWelement
  9. Elementrow=path.getCurrent();
  10. ElementrowSet=row.getParent();
  11. Documentdocument=row.getDocument();
  12. ...
  13. //prunethetree
  14. row.detach();
  15. }
  16. }
  17. );
  18. Documentdocument=reader.read(url);




上面的办法解决了读的问题可是写的问题还没有解决。我命由我不由天(吹牛皮),畅游dom4j的doc文档找到如下几个方法
startDocument()
writeOpen();
writeClose();
endDocument()
动手一试,问题搞定,看来牛皮没白吹。下面是示例代码:

Java代码
  1. /**
  2. *数据写入xml文件
  3. *@paramfilePath目标xml文件的存放路径
  4. *@return
  5. */
  6. publicbooleanwriteXML(StringfilePath){
  7. XMLWriterout;
  8. try{
  9. /*
  10. *创建XMLWriter对象,设置XML编码,解决中文问题。
  11. */
  12. OutputFormatoutputFormat=OutputFormat.createPrettyPrint();
  13. outputFormat.setEncoding("GBK");
  14. out=newXMLWriter(newFileWriter(filePath),outputFormat);
  15. out.startDocument();
  16. ElementrootElement=DocumentHelper.createElement("mans");
  17. out.writeOpen(rootElement);
  18. /*
  19. *向mans节点写入子节点
  20. */
  21. for(inti=0;i<1000000;i++){
  22. Elementman=createManElement(newLong(i),"shuhang"+i);//用于创建节点的方法
  23. out.write(man);
  24. System.out.println("theloopindexis:"+i);
  25. }
  26. out.writeClose(rootElement);
  27. out.endDocument();
  28. out.close();
  29. returntrue;
  30. }catch(IOExceptione){
  31. e.printStackTrace();
  32. returnfalse;
  33. }catch(SAXExceptione){
  34. e.printStackTrace();
  35. returnfalse;
  36. }
  37. }




新问题出现。对于读取数据的方法,在onEnd()方法中只是进行对Element的简单操作而已,若要对Element进行复杂的处理怎么办,如将 Element节点的数据写入数据库,无法在onEnd()方法中加入过多的代码,因为无法通过编译。仔细想了一下dom4j的注册事件处理器应该用的是模板方法,通过钩子将用户的操作加入到模板中去。何不自己写一个事件处理器来完成我们自己的定制操作,代码如下:

Java代码
  1. publicclassManElementHandlerimplementsElementHandler{
  2. publicStringmdbName;
  3. ­
  4. publicManElementHandler(){
  5. }
  6. ­
  7. publicManElementHandler(StringmdbName){
  8. this.mdbName=mdbName;
  9. }
  10. ­
  11. publicbooleansaveMan(Elementelement,StringmdbName){
  12. returntrue;
  13. }
  14. ­
  15. publicvoidonEnd(ElementPatharg0){
  16. Elementrow=arg0.getCurrent();
  17. ElementrowSet=row.getParent();
  18. Documentdocument=row.getDocument();
  19. Elementroot=document.getRootElement();
  20. Iteratorit=root.elementIterator();
  21. while(it.hasNext()){
  22. Elementelement=(Element)it.next();
  23. System.out.println("id:"+element.elementText("id")+"name:"+element.elementText("name"));
  24. saveMan(element,this.mdbName);
  25. }
  26. row.detach();
  27. }
  28. publicvoidonStart(ElementPathpath){
  29. }
  30. }




下面给出完整的实例代码。该实例首先创建一个xml文档,然后读取xml文档中的数据并将数据写入Access数据库中。测试时使用的文件大小为125M未发生内存溢出。

Java代码
  1. //*****************************************************************************************************************
  2. packagecom;
  3. importjava.sql.Connection;
  4. importjava.sql.DriverManager;
  5. /**
  6. *获取Access数据库的连接
  7. *@author佛山无影脚
  8. *@version1.0
  9. *Jul7,20084:35:49PM
  10. */
  11. publicclassAccessMDBUtil{
  12. publicstaticConnectionconnectMdb(StringmdbName){
  13. if(mdbName==null||mdbName.equals("")){
  14. returnnull;
  15. }
  16. try{
  17. Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
  18. Stringdburl="jdbc:odbc:driver={MicrosoftAccessDriver(*.mdb)};DBQ="+mdbName;
  19. Connectionconn=DriverManager.getConnection(dburl);
  20. returnconn;
  21. }catch(Exceptione){
  22. e.printStackTrace();
  23. returnnull;
  24. }
  25. }
  26. }
  27. //*******************************************************************************************************************
  28. //*******************************************************************************************************************
  29. packagecom;
  30. importjava.sql.Connection;
  31. importjava.sql.ResultSet;
  32. importjava.sql.SQLException;
  33. importjava.sql.Statement;
  34. importjava.util.Iterator;
  35. importorg.dom4j.Document;
  36. importorg.dom4j.Element;
  37. importorg.dom4j.ElementHandler;
  38. importorg.dom4j.ElementPath;
  39. /**
  40. *定制的事件处理器
  41. *@author佛山无影脚
  42. *@version1.0
  43. *Jul7,20084:35:49PM
  44. */
  45. publicclassManElementHandlerimplementsElementHandler{
  46. publicStringmdbName;//数据库名称含路径
  47. ­
  48. publicManElementHandler(){
  49. }
  50. ­
  51. publicManElementHandler(StringmdbName){
  52. this.mdbName=mdbName;
  53. }
  54. ­
  55. /**
  56. *将Element节点数据保存到数据库
  57. *@paramelement遍历XML文档时的当前节点
  58. *@parammdbName数据库名称含路径
  59. *@return
  60. */
  61. publicbooleansaveMan(Elementelement,StringmdbName){
  62. System.out.println("themethodsaveManinManElementHandlerisexecute!");
  63. Statementstmt=null;
  64. ResultSetrs=null;
  65. Connectionconn=null;
  66. try{
  67. conn=AccessMDBUtil.connectMdb(mdbName);
  68. stmt=conn.createStatement();
  69. Stringsql="insertintomans(id,name)values("+element.elementText("id")+",'"+element.elementText("name")+"')";
  70. stmt.executeUpdate(sql);
  71. }catch(Exceptione){
  72. e.printStackTrace();
  73. returnfalse;
  74. }finally{
  75. if(rs!=null){
  76. try{
  77. rs.close();
  78. }catch(SQLExceptione){
  79. //TODOAuto-generatedcatchblock
  80. e.printStackTrace();
  81. }
  82. }
  83. if(stmt!=null){
  84. try{
  85. stmt.close();
  86. }catch(SQLExceptione){
  87. //TODOAuto-generatedcatchblock
  88. e.printStackTrace();
  89. }
  90. }
  91. if(conn!=null){
  92. try{
  93. conn.close();
  94. }catch(SQLExceptione){
  95. //TODOAuto-generatedcatchblock
  96. e.printStackTrace();
  97. }
  98. }
  99. }
  100. returntrue;
  101. }
  102. ­
  103. publicvoidonEnd(ElementPatharg0){
  104. Elementrow=arg0.getCurrent();
  105. ElementrowSet=row.getParent();
  106. Documentdocument=row.getDocument();
  107. Elementroot=document.getRootElement();
  108. Iteratorit=root.elementIterator();
  109. while(it.hasNext()){
  110. Elementelement=(Element)it.next();
  111. System.out.println("id:"+element.elementText("id")+"name:"+element.elementText("name"));
  112. saveMan(element,this.mdbName);
  113. }
  114. row.detach();
  115. }
  116. publicvoidonStart(ElementPathpath){
  117. }
  118. }
  119. //*************************************************************************************************************************
  120. //*************************************************************************************************************************
  121. packagecom;
  122. importjava.io.File;
  123. importjava.io.FileWriter;
  124. importjava.io.IOException;
  125. importorg.dom4j.Document;
  126. importorg.dom4j.DocumentException;
  127. importorg.dom4j.DocumentHelper;
  128. importorg.dom4j.Element;
  129. importorg.dom4j.io.OutputFormat;
  130. importorg.dom4j.io.SAXReader;
  131. importorg.dom4j.io.XMLWriter;
  132. importorg.xml.sax.SAXException;
  133. importorg.xml.sax.XMLReader;
  134. /**
  135. *测试
  136. *@author佛山无影脚
  137. *@version1.0
  138. *Jul7,20084:35:49PM
  139. */
  140. publicclassManTest{
  141. /**
  142. *创建man节点
  143. *<man><id>1</id><name>佛山无影脚</name></man>
  144. *@paramid
  145. *@paramname
  146. *@return
  147. */
  148. publicElementcreateManElement(Longid,Stringname){
  149. ElementmanElement=DocumentHelper.createElement("man");
  150. manElement.addElement("id").addText(id.toString());
  151. manElement.addElement("name").addText(name);
  152. returnmanElement;
  153. }
  154. ­
  155. /**
  156. *数据写入xml文件
  157. *@paramfilePath目标xml文件的存放路径
  158. *@return
  159. */
  160. publicbooleanwriteXML(StringfilePath){
  161. XMLWriterout;
  162. try{
  163. /*
  164. *创建XMLWriter对象,设置XML编码,解决中文问题。
  165. */
  166. OutputFormatoutputFormat=OutputFormat.createPrettyPrint();
  167. outputFormat.setEncoding("GBK");
  168. out=newXMLWriter(newFileWriter(filePath),outputFormat);
  169. out.startDocument();
  170. ElementrootElement=DocumentHelper.createElement("mans");
  171. out.writeOpen(rootElement);
  172. /*
  173. *向mans节点写入子节点
  174. */
  175. for(inti=0;i<1000000;i++){
  176. Elementman=this.createManElement(newLong(i),"shuhang"+i);
  177. out.write(man);
  178. System.out.println("theloopindexis:"+i);
  179. }
  180. out.writeClose(rootElement);
  181. out.endDocument();
  182. out.close();
  183. returntrue;
  184. }catch(IOExceptione){
  185. e.printStackTrace();
  186. returnfalse;
  187. }catch(SAXExceptione){
  188. e.printStackTrace();
  189. returnfalse;
  190. }
  191. }
  192. ­
  193. /**
  194. *从xml文件中读取数据,并将数据写入Access数据
  195. *@paramfilePathxml文件的存放路径
  196. *@return
  197. */
  198. publicbooleanreadXML(StringfilePath){
  199. ManElementHandlermanElementHandler=newManElementHandler("F://dom4j//xmlTest.mdb");
  200. SAXReaderreader=newSAXReader();
  201. reader.addHandler("/mans/man",manElementHandler);
  202. Documentdocument=null;
  203. try{
  204. Filefile=newFile(filePath);
  205. document=reader.read(file);
  206. }catch(DocumentExceptione){
  207. e.printStackTrace();
  208. returnfalse;
  209. }
  210. returntrue;
  211. }
  212. ­
  213. ­
  214. publicstaticvoidmain(String[]args){
  215. XMLReaderreader=null;
  216. longstartTime=System.currentTimeMillis();
  217. ManTestmantest=newManTest();
  218. mantest.writeXML("f://dom4j//mans.xml");
  219. mantest.readXML("f://dom4j//mans.xml");
  220. longendTime=System.currentTimeMillis();
  221. System.out.println("isend!themillisis:"+(endTime-startTime));
  222. }
  223. }

你可能感兴趣的:(dom4j)