流式处理和基于树的 XML 解析器在 JAVA 开始时是不是消耗相似数量的内存

Posted

技术标签:

【中文标题】流式处理和基于树的 XML 解析器在 JAVA 开始时是不是消耗相似数量的内存【英文标题】:Do Streaming and Tree-Based XML parsers consume similar amounts of memory at the beginning in JAVA流式处理和基于树的 XML 解析器在 JAVA 开始时是否消耗相似数量的内存 【发布时间】:2014-11-22 19:23:55 【问题描述】:

有两个主要的解析器来读取 XML。

    流式解析器 -(例如:SAX、StAX) 基于树的解析器 -(例如:DOM、AXIOM 等)

据说流式解析器比基于树的解析器使用更少的内存。需要注意的一点是,与基于树的解析器不同,流解析器不提供整个 XML 树以供开发人员导航。在那里,我们可以根据事件进行导航。并且在处理每个事件之后,与该事件关联的数据(xml 内容)可以被处理器从内存中丢弃。

但是,在这两种情况下,我们都必须将整个 XML 内容提供给解析器。因此,在内部,解析器必须将整个 XML 内容存储在内存中以浏览每个节点。那么,我的论点是流式解析器如何比基于树的解析器消耗更少的内存?

    开始读取 XML 时,流式解析器和基于树的解析器消耗的内存量是否相似? 流式解析器使用哪些技术比基于树的解析器消耗更少的内存?

萨克斯:

SAXParserFactory        factory     =   SAXParserFactory.newInstance();
SAXParser               saxPaser    =   factory.newSAXParser();

ResultHandler           handler     =   new ResultHandler();

InputSource             input       =   new InputSource(new StringReader(xml));             
input.setEncoding("utf-8");
saxPaser.parse(input,handler);

StAX:

    XMLInputFactory             inputFactory    = XMLInputFactory.newInstance();
    XMLEventReader              eventReader     = inputFactory.createXMLEventReader(new FileInputStream(configFile));

公理:

    XMLStreamReader             parser                              = XMLInputFactory.newInstance().createXMLStreamReader(new StringBufferInputStream(responseXML));
    OMElement                   documentElement                     = new StAXOMBuilder(parser).getDocumentElement();

参考文献:

http://www.vogella.com/tutorials/JavaXML/article.html http://www.javacodegeeks.com/2012/01/xml-parsing-using-saxparser-with.html http://tutorials.jenkov.com/java-xml/index.html https://www.youtube.com/watch?v=uaclko4rbZQ https://www.youtube.com/watch?v=BVhKoEQmpcA https://www.youtube.com/watch?v=Kvb9B_7W8rs

【问题讨论】:

"在这两种情况下,我们都必须将整个 XML 内容提供给解析器。"这是错误的假设。您通常提供一个输入流,用于将 XML 读取到 SAX 或 StAX 解析器。而且这些解析器不会将整个 XML 加载到内存中。他们流式传输它。 @Seelenvirtuose :但是每次我们将整个 XML 字符串提供给每个解析器。正确的?因此,该字符串必须在内存中才能在解析器中读取。 嗯...我不完全知道“将整个 XML 字符串提供给每个解析器”是什么意思。您提到的所有三个教程都在处理 files 而不是 strings (我没有看 youtube 剪辑)。但是,是的,如果内存中已经有一个 XML 字符串,那么它将在内存中消耗它的全部大小。但这已经是真的没有解析。 【参考方案1】:

我相信你混淆了两个部分:

    开发人员如何将 XML 提供给解析器 解析器如何读取数据

对于第一部分,您有两个选择(实际上不止两个,但我们会考虑最常见的两个)。

    您可以告诉解析器从文件或套接字中读取。在这种情况下,流解析器永远不会在内存中拥有 XML 的完整副本。但是,如果您将 XML 作为字符串加载到内存中,然后将其提供给解析器,那么消耗内存的是您,而不是解析器。它会尽职尽责地“流式传输”您的字符串,而不是保留自己的 XML 内部副本。 对于 DOM 解析器,它确实构建了一个完整的内存树。在你给它一个文件的情况下,实际的文件内容在构建 DOM 结构后会被丢弃。当您提供一个字符串时,在解析结束时,您将拥有新建的 DOM 树加上包含 XML 源的字符串。

如果您不需要在随机方向上导航树,请使用流解析器。否则你将不得不使用 DOM。

【讨论】:

+1。 " 在这种情况下,流解析器在内存中永远不会有 XML 的完整副本。但是,如果您将 XML 作为字符串加载到内存中,然后将其提供给解析器,那么消耗内存的是您,而不是解析器。它将尽职尽责地“流式传输”您的字符串,而不是保留其自己的 XML 内部副本。”吉姆说得好。谢谢。是的。我也觉得我错过了什么。再次感谢您,【参考方案2】:

将诸如 DOM 或 JDOM 之类的树构建库称为“解析器”已变得如此普遍,这真是令人遗憾。这里真的有两个软件:一个解析器(它读取源中的字符序列,分析它,并发出一系列表示句法单元的事件,例如开始和结束标签),以及一个树构建器,它接受来自解析器的事件序列并构建内存树。

因此,您的选择不在两种不同类型的解析器之间。您的选择是让解析器将事件直接传递给您的应用程序,还是让它将事件传递给树构建器,然后将完成的树传递给您的应用程序。

解析器不使用大量内存。树生成器可以。但是树生成器以更容易处理的形式向应用程序提供信息。

【讨论】:

以上是关于流式处理和基于树的 XML 解析器在 JAVA 开始时是不是消耗相似数量的内存的主要内容,如果未能解决你的问题,请参考以下文章

使用 DOM 解析器在 Java 中解析具有 2 个默认命名空间的 XML

使用 Sax Parser、Java 处理 XML 中的空标签

浅谈用java解析xml文档

xml文件解析(使用解析器)

PHP-XML基于流的解析器及其他常用解析器

XML解析入门(Java版)