代码之家  ›  专栏  ›  技术社区  ›  Fazal

stax和dom解析的性能差异

  •  4
  • Fazal  · 技术社区  · 14 年前

    我已经使用DOM很长时间了,因此从性能上讲,DOM解析已经相当不错了。即使在处理大约4-7MB的XML时,解析也很快。我们面对的问题是,一旦开始处理大型XML,内存占用就会变得很大。

    最近我尝试转移到stax(用于XML的流式解析器),它被认为是第二代解析器中的佼佼者(在阅读关于stax的文章时,它说它现在是最快的解析器)。当我尝试了大容量XML的Stax解析器,大约4MB时,内存占用量急剧减少,但解析整个XML并创建Java对象的时间比DOM增加了将近5倍。

    我使用了statx的sjsxp.jar实现。

    在某种程度上,我可以从逻辑上推断,由于解析器的流式性质,性能可能不是非常好,但是减少5次(例如,为这个XML构建对象需要大约8秒的时间,而stax解析平均需要大约40秒)肯定是不可接受的。

    我是否完全错过了一些要点,因为我无法接受这些性能数字

    4 回复  |  直到 13 年前
        1
  •  6
  •   Matt Ball    13 年前
    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米尔斯

    斯塔克斯胜=)

        2
  •  1
  •   StaxMan    14 年前

    尽管这个问题缺乏一些细节,但我敢肯定的是,无论哪种情况,解析速度都不是很慢(dom不是解析器;dom树通常是使用sax或stax解析器构建的),而是上面创建对象的代码。

    有一些高效的自动数据绑定器,包括JAXB(以及适当的设置,Xstream),这可能会有所帮助。它们比dom更快,因为dom(以及jdom、dom4j和xom)的主要性能问题是树模型与pojos相比固有地昂贵——它们基本上是美化的散列图,具有许多指针,便于非类型化遍历,特别是关于内存使用。

    至于解析器,Woodstox比SJSXP更快的stax解析器;如果原始速度很重要的话,aalto甚至更快。但我怀疑主要问题是这里的解析器速度。

        3
  •  0
  •   kazanaki    14 年前

    经典案例 speed/memory tradeoff 在我看来。除了再次尝试SAX(或JDOM)和度量之外,您可以做的也不多。

        4
  •  0
  •   Jayan    14 年前

    尝试用2000米创建一个XML,然后比较数字。我想基于DOM的方法在处理较小的数据时会更快。当数据变大时,stax(或任何基于sax的方法)将成为选项。

    (我们处理3G或大型文件..DOM甚至不启动应用程序。)