溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JAVA通過XPath解析XML性能比較詳解

發(fā)布時(shí)間:2020-09-02 01:45:13 來源:腳本之家 閱讀:324 作者:王中秋 欄目:編程語言

最近在做一個(gè)小項(xiàng)目,使用到XML文件解析技術(shù),通過對該技術(shù)的了解和使用,總結(jié)了以下內(nèi)容。

1 XML文件解析的4種方法

通常解析XML文件有四種經(jīng)典的方法?;镜慕馕龇绞接袃煞N,一種叫SAX,另一種叫DOM。SAX是基于事件流的解析,DOM是基于XML文檔樹結(jié)構(gòu)的解析。在此基礎(chǔ)上,為了減少DOM、SAX的編碼量,出現(xiàn)了JDOM,其優(yōu)點(diǎn)是,20-80原則(帕累托法則),極大減少了代碼量。通常情況下JDOM使用時(shí)滿足要實(shí)現(xiàn)的功能簡單,如解析、創(chuàng)建等要求。但在底層,JDOM還是使用SAX(最常用)、DOM、Xanan文檔。另外一種是DOM4J,是一個(gè)非常非常優(yōu)秀的Java XML API,具有性能優(yōu)異、功能強(qiáng)大和極端易用的特點(diǎn),同時(shí)它也是一個(gè)開放源代碼的軟件。如今你可以看到越來越多的 Java 軟件都在使用 DOM4J 來讀寫 XML,特別值得一提的是連 Sun 的 JAXM 也在用 DOM4J。

2 XPath簡單介紹

XPath 是一門在 XML 文檔中查找信息的語言。XPath 用于在 XML 文檔中通過元素和屬性進(jìn)行導(dǎo)航,并對元素和屬性進(jìn)行遍歷。XPath 是 W3C XSLT 標(biāo)準(zhǔn)的主要元素,并且 XQuery 和 XPointer 同時(shí)被構(gòu)建于 XPath 表達(dá)之上。因此,對 XPath 的理解是很多高級 XML 應(yīng)用的基礎(chǔ)。XPath非常類似對數(shù)據(jù)庫操作的SQL語言,或者說JQuery,它可以方便開發(fā)者抓起文檔中需要的東西。其中DOM4J也支持XPath的使用。

3 DOM4J使用XPath

DOM4J使用XPath解析XML文檔是,首先需要在項(xiàng)目中引用兩個(gè)JAR包:

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

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

3.1 命名空間(namespace)的干擾

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

<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()函數(shù)):使用XPath語法中自帶的local-name() 和 namespace-uri() 指定你要使用的節(jié)點(diǎn)名和命名空間。 XPath表達(dá)式書寫較為麻煩。

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

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

第四種方法(read4()函數(shù)):方法和第三種一樣,但是XPath表達(dá)式不同(程序具體體現(xiàn)),主要是為了檢驗(yàn)XPath表達(dá)式的不同,主要指完整程度,是否會(huì)對檢索效率產(chǎn)生影響。(以上四種方法均通過DOM4J結(jié)合XPath對XML文件進(jìn)行解析)

第五種方法(read5()函數(shù)):使用DOM結(jié)合XPath對XML文件進(jìn)行解析,主要是為了檢驗(yàn)性能差異。

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

package XPath;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * DOM4J DOM XML XPath
 * @author hao
 */
public class TestDom4jXpath {
  public static void main(String[] args) {
    read1();
    read2();
    read3();
    read4();//read3()方法一樣,但是XPath表達(dá)式不同
    read5();
  }
  
  public static void read1() {
    /*
     * use local-name() and namespace-uri() in XPath
     */
    try {
      long startTime=System.currentTimeMillis();
      SAXReader reader = new SAXReader();
      InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
      Document doc = reader.read(in);
      /*String xpath ="http://*[local-name()='Workbook' and namespace-uri()='urn:schemas-microsoft-com:office:spreadsheet']"
          + "/*[local-name()='Worksheet']"
          + "/*[local-name()='Table']"
          + "/*[local-name()='Row'][4]"
          + "/*[local-name()='Cell'][3]"
          + "/*[local-name()='Data'][1]";*/
      String xpath ="http://*[local-name()='Row'][4]/*[local-name()='Cell'][3]/*[local-name()='Data'][1]";
      System.err.println("=====use local-name() and namespace-uri() in XPath====");
      System.err.println("XPath:" + xpath);
      @SuppressWarnings("unchecked")
      List<Element> list = doc.selectNodes(xpath);
      for(Object o:list){ 
        Element e = (Element) o; 
        String show=e.getStringValue();
        System.out.println("show = " + show); 
      long endTime=System.currentTimeMillis();
      System.out.println("程序運(yùn)行時(shí)間: "+(endTime-startTime)+"ms");
      } 
    } catch (DocumentException e) {
      e.printStackTrace();
    }
  }
  
  public static void read2() {
    /*
     * set xpath namespace(setNamespaceURIs)
     */
    try {
      long startTime=System.currentTimeMillis();
      Map map = new HashMap();
      map.put("Workbook","urn:schemas-microsoft-com:office:spreadsheet");
      SAXReader reader = new SAXReader();
      InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
      Document doc = reader.read(in);
      String xpath ="http://Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]";
      System.err.println("=====use setNamespaceURIs() to set xpath namespace====");
      System.err.println("XPath:" + xpath);
      XPath x = doc.createXPath(xpath);
      x.setNamespaceURIs(map);
      @SuppressWarnings("unchecked")
      List<Element> list = x.selectNodes(doc);
      for(Object o:list){ 
        Element e = (Element) o; 
        String show=e.getStringValue();
        System.out.println("show = " + show);  
      long endTime=System.currentTimeMillis();
      System.out.println("程序運(yùn)行時(shí)間: "+(endTime-startTime)+"ms");
      } 
    } catch (DocumentException e) {
      e.printStackTrace();
    }
  }
  
  public static void read3() {
    /*
     * set DocumentFactory() namespace(setXPathNamespaceURIs)
     */
    try {
      long startTime=System.currentTimeMillis();
      Map map = new HashMap();
      map.put("Workbook","urn:schemas-microsoft-com:office:spreadsheet");
      SAXReader reader = new SAXReader();
      InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
      reader.getDocumentFactory().setXPathNamespaceURIs(map);
      Document doc = reader.read(in);
      String xpath ="http://Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]";
      System.err.println("=====use setXPathNamespaceURIs() to set DocumentFactory() namespace====");
      System.err.println("XPath:" + xpath);
      @SuppressWarnings("unchecked")
      List<Element> list = doc.selectNodes(xpath);
      for(Object o:list){ 
        Element e = (Element) o; 
        String show=e.getStringValue();
        System.out.println("show = " + show);
      long endTime=System.currentTimeMillis();
      System.out.println("程序運(yùn)行時(shí)間: "+(endTime-startTime)+"ms");  
      } 
    } catch (DocumentException e) {
      e.printStackTrace();
    }
  }
  
  public static void read4() {
    /*
     * 同read3()方法一樣,但是XPath表達(dá)式不同
     */
    try {
      long startTime=System.currentTimeMillis();
      Map map = new HashMap();
      map.put("Workbook","urn:schemas-microsoft-com:office:spreadsheet");
      SAXReader reader = new SAXReader();
      InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
      reader.getDocumentFactory().setXPathNamespaceURIs(map);
      Document doc = reader.read(in);
      String xpath ="http://Workbook:Worksheet/Workbook:Table/Workbook:Row[4]/Workbook:Cell[3]/Workbook:Data[1]";
      System.err.println("=====use setXPathNamespaceURIs() to set DocumentFactory() namespace====");
      System.err.println("XPath:" + xpath);
      @SuppressWarnings("unchecked")
      List<Element> list = doc.selectNodes(xpath);
      for(Object o:list){ 
        Element e = (Element) o; 
        String show=e.getStringValue();
        System.out.println("show = " + show);
      long endTime=System.currentTimeMillis();
      System.out.println("程序運(yùn)行時(shí)間: "+(endTime-startTime)+"ms");  
      } 
    } catch (DocumentException e) {
      e.printStackTrace();
    }
  }
  
  public static void read5() {
    /*
     * DOM and XPath
     */
    try {
      long startTime=System.currentTimeMillis();
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      dbf.setNamespaceAware(false);
      DocumentBuilder builder = dbf.newDocumentBuilder();
      InputStream in = TestDom4jXpath.class.getClassLoader().getResourceAsStream("XPath\\XXX.xml");
      org.w3c.dom.Document doc = builder.parse(in);
      XPathFactory factory = XPathFactory.newInstance();
      javax.xml.xpath.XPath x = factory.newXPath();
      //選取所有class元素的name屬性
      String xpath = "http://Workbook/Worksheet/Table/Row[4]/Cell[3]/Data[1]";
      System.err.println("=====Dom XPath====");
      System.err.println("XPath:" + xpath);
      XPathExpression expr = x.compile(xpath);
      NodeList nodes = (NodeList)expr.evaluate(doc, XPathConstants.NODE);
      for(int i = 0; i<nodes.getLength();i++) {
        System.out.println("show = " + nodes.item(i).getNodeValue());
      long endTime=System.currentTimeMillis();
      System.out.println("程序運(yùn)行時(shí)間: "+(endTime-startTime)+"ms");
      }
    } catch(XPathExpressionException e) {
      e.printStackTrace();
    } catch(ParserConfigurationException e) {
      e.printStackTrace();
    } catch(SAXException e) {
      e.printStackTrace();
    } catch(IOException e) {
      e.printStackTrace();
    }
  }
}

3.3 不同方法的性能比較

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

JAVA通過XPath解析XML性能比較詳解

圖1 XPath使用性能對比

方法名稱

平均運(yùn)行時(shí)間

XPath表達(dá)式

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 平均性能統(tǒng)計(jì)

由以上性能對比可知:

1、read4()方法運(yùn)行時(shí)間最短,即運(yùn)用DOM4J方法調(diào)用全路徑(從根節(jié)點(diǎn)出發(fā))XPath表達(dá)式解析XML文件耗時(shí)最短;

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI