在Java中解析大型XML响应

时间:2011-06-14 13:35:18

标签: java xml web-services soap

我有一个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来处理解析,并以相同的方式构建我的Document部分。有没有人有其他解决方案或这是我最好的选择?

谢谢, 贾里德

6 个答案:

答案 0 :(得分:4)

在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。

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

你可以查看一个像Nux这样的库,它可以让你将XML流与XPath结合起来,只提取你想要的值。可能值得研究,而不是试图写一些自定义的东西。

答案 5 :(得分:0)

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

java -Xms64m -Xmx256m

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