JAVA通過XPath解析XML性能比較

轉自【http://www.cnblogs.com/mouse-coder/p/3451243.html】

最近在做一個小項目,使用到XML文件解析技術,通過對該技術的瞭解和使用,總結了以下內容。

1 XML文件解析的4種方法

       通常解析XML文件有四種經典的方法。基本的解析方式有兩種,一種叫SAX,另一種叫DOM。SAX是基於事件流的解析,DOM是基於XML文檔樹結構的解析。在此基礎上,爲了減少DOM、SAX的編碼量,出現了JDOM,其優點是,20-80原則(帕累托法則),極大減少了代碼量。通常情況下JDOM使用時滿足要實現的功能簡單,如解析、創建等要求。但在底層,JDOM還是使用SAX(最常用)、DOM、Xanan文檔。另外一種是DOM4J,是一個非常非常優秀的Java XML API,具有性能優異、功能強大和極端易用的特點,同時它也是一個開放源代碼的軟件。如今你可以看到越來越多的 Java 軟件都在使用 DOM4J 來讀寫 XML,特別值得一提的是連 Sun 的 JAXM 也在用 DOM4J。具體四種方法的使用,百度一下,會有衆多詳細的介紹。可以參考SMCwwh對以上技術的詳細介紹,http://blog.csdn.net/smcwwh/article/details/7183869#part3

2 XPath簡單介紹

       XPath 是一門在 XML 文檔中查找信息的語言。XPath 用於在 XML 文檔中通過元素和屬性進行導航,並對元素和屬性進行遍歷。XPath 是 W3C XSLT 標準的主要元素,並且 XQuery 和 XPointer 同時被構建於 XPath 表達之上。因此,對 XPath 的理解是很多高級 XML 應用的基礎。XPath非常類似對數據庫操作的SQL語言,或者說JQuery,它可以方便開發者抓起文檔中需要的東西。其中DOM4J也支持XPath的使用。XPath的具體使用教程可以參考http://www.w3school.com.cn/xpath/index.asp

3 DOM4J使用XPath

         DOM4J使用XPath解析XML文檔是,首先需要在項目中引用兩個JAR包:

       dom4j-1.6.1.jar:DOM4J軟件包,下載地址http://sourceforge.net/projects/dom4j/

       jaxen-xx.xx.jar:通常不添加此包,會引發異常(java.lang.NoClassDefFoundError: org/jaxen/JaxenException),下載地址http://www.jaxen.org/releases.html

3.1 命名空間(namespace)的干擾

       在處理由excel文件或其他格式文件轉換的xml文件時,通常會遇到通過XPath解析得不到結果的情況。這種情況通常是由於命名空間的存在導致的。以下述內容的XML文件爲例,通過XPath=" // Workbook/ Worksheet / Table / Row[1]/ Cell[1]/Data[1] "進行簡單的檢索,通常是沒有結果出現的。這就是由於命名空間namespace(xmlns="urn:schemas-microsoft-com:office:spreadsheet")導致的。

複製代碼
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
  <Worksheet ss:Name="Sheet1">
    <Table ss:ExpandedColumnCount="81" ss:ExpandedRowCount="687" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="52.5" ss:DefaultRowHeight="15.5625">
      <Row ss:AutoFitHeight="0">
         <Cell>
          <Data ss:Type="String">敲代碼的耗子</Data>
         </Cell> 
      </Row>
      <Row ss:AutoFitHeight="0">
         <Cell>
          <Data ss:Type="String">Sunny</Data>
         </Cell> 
      </Row>
    </Table>
  </Worksheet>
</Workbook>
複製代碼

3.2 XPath對帶有命名空間的xml文件解析

       第一種方法(read1()函數):使用XPath語法中自帶的local-name() 和 namespace-uri() 指定你要使用的節點名和命名空間。 XPath表達式書寫較爲麻煩。

       第二種方法(read2()函數):設置XPath的命名空間,利用setNamespaceURIs()函數。

       第三種方法(read3()函數):設置DocumentFactory()的命名空間 ,使用的函數是setXPathNamespaceURIs()。二和三兩種方法的XPath表達式書寫相對簡單。

       第四種方法(read4()函數):方法和第三種一樣,但是XPath表達式不同(程序具體體現),主要是爲了檢驗XPath表達式的不同,主要指完整程度,是否會對檢索效率產生影響。

       (以上四種方法均通過DOM4J結合XPath對XML文件進行解析)

       第五種方法(read5()函數):使用DOM結合XPath對XML文件進行解析,主要是爲了檢驗性能差異。

       沒有什麼能夠比代碼更能說明問題的了!果斷上代碼!

       

複製代碼
  1 package XPath;
  2 import java.io.IOException;
  3 import java.io.InputStream;
  4 import java.util.HashMap;
  5 import java.util.List;
  6 import java.util.Map;
  7 
  8 import javax.xml.parsers.DocumentBuilder;
  9 import javax.xml.parsers.DocumentBuilderFactory;
 10 import javax.xml.parsers.ParserConfigurationException;
 11 import javax.xml.xpath.XPathConstants;
 12 import javax.xml.xpath.XPathExpression;
 13 import javax.xml.xpath.XPathExpressionException;
 14 import javax.xml.xpath.XPathFactory;
 15 
 16 import org.dom4j.Document;
 17 import org.dom4j.DocumentException;
 18 import org.dom4j.Element;
 19 import org.dom4j.XPath;
 20 import org.dom4j.io.SAXReader;
 21 import org.w3c.dom.NodeList;
 22 import org.xml.sax.SAXException;
 23 
 24 /**
 25  * DOM4J DOM XML XPath
 26  * @author hao
 27  */
 28 public class TestDom4jXpath {
 29     public static void main(String[] args) {
 30         read1();
 31         read2();
 32         read3();
 33         read4();//read3()方法一樣,但是XPath表達式不同
 34         read5();
 35     }
 36     
 37     public static void read1() {
 38         /*
 39          * use local-name() and namespace-uri() in XPath
 40          */
 41         try {
 42             long startTime=System.currentTimeMillis();
 43             SAXReader reader = new SAXReader();
 44             InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
 45             Document doc = reader.read(in);
 46             /*String xpath ="//*[local-name()='Workbook' and namespace-uri()='urn:schemas-microsoft-com:office:spreadsheet']"
 47                     + "/*[local-name()='Worksheet']"
 48                     + "/*[local-name()='Table']"
 49                     + "/*[local-name()='Row'][4]"
 50                     + "/*[local-name()='Cell'][3]"
 51                     + "/*[local-name()='Data'][1]";*/
 52             String xpath ="//*[local-name()='Row'][4]/*[local-name()='Cell'][3]/*[local-name()='Data'][1]";
 53             System.err.println("=====use local-name() and namespace-uri() in XPath====");
 54             System.err.println("XPath:" + xpath);
 55             @SuppressWarnings("unchecked")
 56             List<Element> list = doc.selectNodes(xpath);
 57             for(Object o:list){  
 58                 Element e = (Element) o;  
 59                 String show=e.getStringValue();
 60                 System.out.println("show = " + show);  
 61             long endTime=System.currentTimeMillis();
 62             System.out.println("程序運行時間: "+(endTime-startTime)+"ms");
 63             }  
 64         } catch (DocumentException e) {
 65             e.printStackTrace();
 66         }
 67     }
 68     
 69     public static void read2() {
 70         /*
 71          * set xpath namespace(setNamespaceURIs)
 72          */
 73         try {
 74             long startTime=System.currentTimeMillis();
 75             Map map = new HashMap();
 76             map.put("Workbook","urn:schemas-microsoft-com:office:spreadsheet");
 77             SAXReader reader = new SAXReader();
 78             InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
 79             Document doc = reader.read(in);
 80             String xpath ="//Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]";
 81             System.err.println("=====use setNamespaceURIs() to set xpath namespace====");
 82             System.err.println("XPath:" + xpath);
 83             XPath x = doc.createXPath(xpath);
 84             x.setNamespaceURIs(map);
 85             @SuppressWarnings("unchecked")
 86             List<Element> list = x.selectNodes(doc);
 87             for(Object o:list){  
 88                 Element e = (Element) o;  
 89                 String show=e.getStringValue();
 90                 System.out.println("show = " + show);   
 91             long endTime=System.currentTimeMillis();
 92             System.out.println("程序運行時間: "+(endTime-startTime)+"ms");
 93             }  
 94         } catch (DocumentException e) {
 95             e.printStackTrace();
 96         }
 97     }
 98     
 99     public static void read3() {
100         /*
101          * set DocumentFactory() namespace(setXPathNamespaceURIs)
102          */
103         try {
104             long startTime=System.currentTimeMillis();
105             Map map = new HashMap();
106             map.put("Workbook","urn:schemas-microsoft-com:office:spreadsheet");
107             SAXReader reader = new SAXReader();
108             InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
109             reader.getDocumentFactory().setXPathNamespaceURIs(map);
110             Document doc = reader.read(in);
111             String xpath ="//Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]";
112             System.err.println("=====use setXPathNamespaceURIs() to set DocumentFactory() namespace====");
113             System.err.println("XPath:" + xpath);
114             @SuppressWarnings("unchecked")
115             List<Element> list = doc.selectNodes(xpath);
116             for(Object o:list){  
117                 Element e = (Element) o;  
118                 String show=e.getStringValue();
119                 System.out.println("show = " + show);
120             long endTime=System.currentTimeMillis();
121             System.out.println("程序運行時間: "+(endTime-startTime)+"ms");    
122             }  
123         } catch (DocumentException e) {
124             e.printStackTrace();
125         }
126     }
127     
128     public static void read4() {
129         /*
130          * 同read3()方法一樣,但是XPath表達式不同
131          */
132         try {
133             long startTime=System.currentTimeMillis();
134             Map map = new HashMap();
135             map.put("Workbook","urn:schemas-microsoft-com:office:spreadsheet");
136             SAXReader reader = new SAXReader();
137             InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
138             reader.getDocumentFactory().setXPathNamespaceURIs(map);
139             Document doc = reader.read(in);
140             String xpath ="//Workbook:Worksheet/Workbook:Table/Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]";
141             System.err.println("=====use setXPathNamespaceURIs() to set DocumentFactory() namespace====");
142             System.err.println("XPath:" + xpath);
143             @SuppressWarnings("unchecked")
144             List<Element> list = doc.selectNodes(xpath);
145             for(Object o:list){  
146                 Element e = (Element) o;  
147                 String show=e.getStringValue();
148                 System.out.println("show = " + show);
149             long endTime=System.currentTimeMillis();
150             System.out.println("程序運行時間: "+(endTime-startTime)+"ms");    
151             }  
152         } catch (DocumentException e) {
153             e.printStackTrace();
154         }
155     }
156     
157     public static void read5() {
158         /*
159          * DOM and XPath
160          */
161         try {
162             long startTime=System.currentTimeMillis();
163             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
164             dbf.setNamespaceAware(false);
165             DocumentBuilder builder = dbf.newDocumentBuilder();
166             InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
167             org.w3c.dom.Document doc = builder.parse(in);
168             XPathFactory factory = XPathFactory.newInstance();
169             javax.xml.xpath.XPath x = factory.newXPath();
170             //選取所有class元素的name屬性
171             String xpath = "//Workbook/Worksheet/Table/Row[4]/Cell[3]/Data[1]";
172             System.err.println("=====Dom XPath====");
173             System.err.println("XPath:" + xpath);
174             XPathExpression expr = x.compile(xpath);
175             NodeList nodes = (NodeList)expr.evaluate(doc, XPathConstants.NODE);
176             for(int i = 0; i<nodes.getLength();i++) {
177                 System.out.println("show = " + nodes.item(i).getNodeValue());
178             long endTime=System.currentTimeMillis();
179             System.out.println("程序運行時間: "+(endTime-startTime)+"ms");
180             }
181         } catch(XPathExpressionException e) {
182             e.printStackTrace();
183         } catch(ParserConfigurationException e) {
184             e.printStackTrace();
185         } catch(SAXException e) {
186             e.printStackTrace();
187         } catch(IOException e) {
188             e.printStackTrace();
189         }
190     }
191 }
複製代碼

3.3 不同方法的性能比較

       爲了比較幾種方法的解析性能,實驗過程中使用了6M以上大小,7萬行以上的XML文件(XXX.xml)進行10輪測試,如下所述:

 

圖1 XPath使用性能對比

方法名稱

平均運行時間

XPath表達式

read1()

1663ms

//*[local-name()='Row'][4]/*[local-name()='Cell'][3]/*[local-name()='Data'][1]

read2()

2184ms

//Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]

read3()

601ms

//Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]

read4()

472ms

//Workbook:Worksheet/Workbook:Table/Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]

read5()

1094ms

//Workbook/Worksheet/Table/Row[4]/Cell[3]/Data[1]

表1 平均性能統計

       由以上性能對比可知:

       1、read4()方法運行時間最短,即運用DOM4J方法調用全路徑(從根節點出發)XPath表達式解析XML文件耗時最短;

       2、運用DOM解析方法所使用的XPath表達式最爲簡單(可以寫作//Row[4]/Cell[3]/Data[1]),因DOM中可以通過setNamespaceAware(false)方法使命名空間失效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章