【问题标题】:Parsing large XML response in Java在 Java 中解析大型 XML 响应
【发布时间】:2011-06-14 13:35:18
【问题描述】:

我有一个 Java 程序向我无法修改的 Web 服务发出请求。来自其中一个请求的响应可能非常大,如果我尝试将其解析为 Document 对象,堆内存就会耗尽。为了解决这个问题,我将响应逐块读取到 byte[] 缓冲区并将其写入磁盘。然后我计划逐行扫描文件并从我找到的每个元素中构建 Document 对象(这些是我需要的唯一响应元素):

StringBuilder sb = null;
String line = null;

while( (line = reader.readLine()) != null ){
    if(line.trim().equals("<bond>")){
        sb = new StringBuilder(line);
    }
    else if(line.trim().equals("</bond>")){
        Document doc = builder.parse(sb.toString());
        // Process doc
    }
    else{
        sb.append(line);
    }
}

不幸的是,换行符似乎在响应中转换为空格,所以一切都是一条巨大的线。我正在考虑的一种解决方案是使用 SAX 来处理解析,并以相同的方式构建我的文档片段。有没有人有其他解决方案或者这是我最好的选择?

谢谢, 贾里德

【问题讨论】:

  • Java xss 在大多数机器上通常为 3mb。要耗尽堆,您的响应应该大约大于 3mb,这在 imo 中是巨大的。但是,如果您的响应仅略大于 3mb,并且您有时会进入 java.lang.StackOverflowError,您可能希望将 xss 选项稍微增加,例如 4mb。例如,在我的 CentOS 上,我将它设置为 5mb,因为我用递归做了很多事情。但是,如果您决定坚持从 Document 对象中读取它,那么 SAX 解析器是实现 imo 的合理方式。请记住,就 CPU 周期而言,这将是双倍的工作。

标签: java xml web-services soap


【解决方案1】:

在 Java 中解析 XML 文档有不同的 API。您似乎正在使用 DOM API。它读取整个 XML 文档并将其转换为节点树;你会得到一个包含所有这些节点的 Document 对象。 DOM API 的优点是相当容易使用,但缺点是如果 XML 很大,所有这些节点都会占用大量内存,正如您所注意到的。

还有 SAX API,它的工作方式不同。这通过回调机制工作:您告诉 XML 解析器您希望在遇到 XML 文件中的开始或结束标记或数据时被调用。然后你在你的回调方法中决定你想要做什么,你只存储你需要的数据。优点是可以扩展到大型文档,因为整个 XML 树不需要驻留在内存中。缺点是这个API级别较低,使用起来比较麻烦。

还有StAX,它被设计为介于 DOM 和 SAX API 之间的东西。

如果您需要处理大型 XML 文档,最好使用 SAX 或 StAX API 而不是 DOM API。

【讨论】:

    【解决方案2】:

    如果您想使用 SAX 或 DOM 解析器,SAX 解析器可能是您的最佳选择。它不会将 xml 存储在内存中,因此它能够处理更大的 XML 文件。

    【讨论】:

      【解决方案3】:

      如果响应很大,是的,SAX 解析器会比较合适,否则在创建 DOM 结构时会再次耗尽内存。

      我还可以推荐用于将 XML 转换为其他形式的 Smooks 框架。它非常适合处理非常大的数据集,并且预先内置了很多东西(http://www.smooks.org)。 Smooks 允许您指定使用 XML 结构的哪些部分来生成新的 Java 对象、XML 或其他内容。

      【解决方案4】:

      我认为使用 SAXBuilder 和 XPath 可能比 while 循环更好。
      这些线上的东西 -

      Document doc = new SAXBuilder().build(new StringReader(xmlStr));
      XPath xPath = XPath.newInstance("/*/YourElement");
      Element ele = xPath.selectSingleNode(doc);
      ele.getChild("ChildElement");
      

      【讨论】:

        【解决方案5】:

        您可以查看诸如 Nux 之类的库,它可以让您将 XML 流式传输与 XPath 结合起来以仅提取您想要的值。它可能值得研究而不是尝试编写自定义内容。

        【讨论】:

          【解决方案6】:

          如果堆大小有问题,您可以尝试使用以下选项来增加它:

          java -Xms64m -Xmx256m

          这将为您提供 64MB 和最大 256MB 的起始堆大小。您可以使用其他值。这具有不需要任何代码更改的优点。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-02-14
            • 2023-03-18
            • 1970-01-01
            • 1970-01-01
            • 2014-04-17
            • 2015-11-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多