2010-03-26 85 views
4

我一直在使用DOM很長一段時間,因爲這樣的DOM解析性能方面已經很不錯了。即使在處理大約4-7 MB的XML時,解析速度也很快。我們面對DOM的問題是一旦我們開始處理大型XML時,內存佔用就會變得巨大。Stax和DOM解析之間的性能差異

最近,我嘗試轉向Stax(Streaming parsers for XML),它們被認爲是第二代解析器(閱讀關於Stax它說它是現在最快的解析器)。當我嘗試使用大型XML的Stax解析器時,大約4MB的內存佔用量明顯減少了,但是花費時間解析整個XML並創建了java對象,使其增加了將近5倍的DOM。

我使用了Stax的sjsxp.jar實現。

我可以從邏輯上推論,由於流解析器的流式性質,性能可能不是非常好,但會減少5次(例如,DOM需要大約8秒才能爲此XML構建對象,而Stax解析需要平均40秒)肯定不會被接受。

我錯過了一些點在這裏完全因爲我無法知道如何面對這些性能數據愚見的speed/memory tradeoff

+1

你能否提供更多細節?你用什麼算法來消耗你的XML和DOM,以及你用什麼算法來消費StAX事件?根據我的經驗,編寫代碼來消費StAX事件比較困難,但性能始終優於DOM。 – dimitarvp 2010-03-26 12:22:22

+0

您是使用遊標API還是事件迭代器API? – carlsborg 2010-08-05 13:29:13

+0

我強烈建議使用合適的分析器來查找瓶頸,否則您會花費年齡追逐野蠻的猜測。 – skaffman 2010-08-30 17:31:20

回答

6
package parsers; 

/** 
* 
* @author Arthur Kushman 
*/ 

import java.io.File; 
import java.io.IOException; 

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 

import org.w3c.dom.Document; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 
import org.w3c.dom.Element; 


public class DOMTest { 

    public static void main(String[] args) { 
    long time1 = System.currentTimeMillis(); 
    try { 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    DocumentBuilder db = dbf.newDocumentBuilder(); 
    Document doc = db.parse(new File("/Users/macpro/Desktop/myxml.xml")); 
    doc.getDocumentElement().normalize(); 
    // System.out.println("Root Element: "+doc.getDocumentElement().getNodeName()); 
    NodeList nodeList = doc.getElementsByTagName("input"); 
    // System.out.println("Information of all elements in input"); 

    for (int s=0;s<nodeList.getLength();s++) { 
     Node firstNode = nodeList.item(s); 
     if (firstNode.getNodeType() == Node.ELEMENT_NODE) { 
     Element firstElement = (Element)firstNode; 
     NodeList firstNameElementList = firstElement.getElementsByTagName("href"); 
     Element firstNameElement = (Element)firstNameElementList.item(0); 
     NodeList firstName = firstNameElement.getChildNodes(); 
     System.out.println("First Name: "+((Node)firstName.item(s)).getNodeValue());   
     } 
    } 


    } catch (Exception ex) { 
    System.out.println(ex.getMessage()); 
    System.exit(1); 
    } 
    long time2 = System.currentTimeMillis() - time1; 
    System.out.println(time2); 
    } 

} 

45廠

package parsers; 

/** 
* 
* @author Arthur Kushman 
*/ 
import javax.xml.stream.*; 
import java.io.*; 
import javax.xml.namespace.QName; 

public class StAXTest { 

    public static void main(String[] args) throws Exception { 
    long time1 = System.currentTimeMillis(); 
    XMLInputFactory factory = XMLInputFactory.newInstance(); 
    // factory.setXMLReporter(myXMLReporter); 
    XMLStreamReader reader = factory.createXMLStreamReader(
      new FileInputStream(
      new File("/Users/macpro/Desktop/myxml.xml"))); 

    /*String encoding = reader.getEncoding(); 

    System.out.println("Encoding: "+encoding); 

    while (reader.hasNext()) { 
     int event = reader.next(); 
     if (event == XMLStreamConstants.START_ELEMENT) { 
     QName element = reader.getName(); 
     // String text = reader.getText(); 
     System.out.println("Element: "+element); 
     // while (event != XMLStreamConstants.END_ELEMENT) { 
      System.out.println("Text: "+reader.getLocalName()); 
     // } 
     } 
    }*/ 

    try { 
    int inElement = 0; 
    for (int event = reader.next();event != XMLStreamConstants.END_DOCUMENT; 
    event = reader.next()) { 
     switch (event) { 
     case XMLStreamConstants.START_ELEMENT: 
      if (isElement(reader.getLocalName(), "href")) { 
      inElement++; 
      } 
      break; 
     case XMLStreamConstants.END_ELEMENT: 
      if (isElement(reader.getLocalName(), "href")) { 
      inElement--; 
      if (inElement == 0) System.out.println(); 
      } 
      break; 
     case XMLStreamConstants.CHARACTERS: 
      if (inElement>0) System.out.println(reader.getText()); 
      break; 
     case XMLStreamConstants.CDATA: 
      if (inElement>0) System.out.println(reader.getText()); 
      break; 
     } 
    } 
    reader.close(); 
    } catch (XMLStreamException ex) { 
    System.out.println(ex.getMessage()); 
    System.exit(1); 
    } 
    // System.out.println(System.currentTimeMillis()); 
    long time2 = System.currentTimeMillis() - time1; 
    System.out.println(time2); 
} 

    public static boolean isElement(String name, String element) { 
    if (name.equals(element)) return true; 
    return false; 
    } 

} 

23廠

StAX的勝利=)

+0

感謝您的詳細分析 – Fazal 2010-09-21 19:08:06

0

經典案例。除了嘗試使用SAX(或JDOM)並再次測量外,您可以做的並不多。

0

嘗試使用2000M創建XML,然後比較數字。我猜想基於DOM的方法會在更小的數據上工作得更快。隨着數據變大,Stax(或任何基於sax的方法)將成爲選項。

(我們應對3G或大型文件.. DOM甚至不啓動應用程序。)

1

雖然問題缺少一些細節,我敢肯定,答案是,它不是解析是緩慢的在任大小寫(DOM不是解析器; DOM樹通常是使用SAX或Stax解析器構建的),但上面的代碼創建對象。

有高效的自動數據綁定器,包括JAXB(並具有適當的設置,XStream),這可以幫助。它們比DOM更快,因爲DOM(和JDOM,Dom4j和XOM)的主要性能問題是,與POJO相比,樹模型本質上昂貴 - 它們基本上是榮耀化的HashMaps,有很多方便無類型遍歷的指針;尤其是內存使用情況。對於解析器,Woodstox是更快的Stax解析器,即Sjsxp;如果原始速度是本質的話,阿爾託更快。但我懷疑主要問題是解析器速度在這裏。

相關問題