我有一个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部分。有没有人有其他解决方案或这是我最好的选择?
谢谢, 贾里德
答案 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。您可以使用其他值。这具有不需要任何代码改变的优点。