我正在尝试解析和替换大型 xml 文件中的值,每个文件大约 45MB。我这样做的方式是:
private void replaceData(File xmlFile, File out)
{
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
DocumentBuilder db = df.newDocumentBuilder();
Document xmlDoc = db.parse(xmlFile);
xmlDoc.getDocumentElement().normalize();
Node allData = xmlDoc.getElementsByTagName("Data").item(0);
Element ctrlData = getSubElement(allData, "ctrlData");
NodeList subData = ctrlData.getElementsByTagName("SubData");
int len = subData.getLength();
for (int logIndex = 0; logIndex < len; logIndex++) {
Node log = subData.item(logIndex);
Element info = getSubElement(log, "info");
Element value = getSubElement(info, "dailyInfo");
Node valueNode = value.getElementsByTagName("value").item(0);
valueNode.setTextContent("blah");
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
DOMSource s = new DOMSource(xmlDoc);
StreamResult r = new StreamResult(out);
t.transform(s, r);
} catch (TransformerException | ParserConfigurationException | SAXException | IOException e) {
throw e;
}
}
private static Element getSubElement(Node node, String elementName)
{
return (Element)((Element)node).getElementsByTagName(elementName).item(0);
}
我注意到随着 for 循环的深入,它花费的时间越长,平均 100k 个节点需要 2 多个小时,而如果我只是手动分解 1k 个较小的 block ,则需要 ~10s .此文档的解析方式是否存在效率低下的问题?
----编辑----
根据对此的评论和回答,我转而使用 Sax 和 XmlStreamWriter。此处引用/示例:http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/
在转为使用 SAX 后,replaceData 函数的内存使用不会扩展到 XML 文件的大小,并且 XML 文件处理时间平均约为 18 秒。
最佳答案
正如人们在评论中提到的,将整个 DOM
加载到内存中,尤其是对于大型 XML,效率非常低,因此更好的方法是使用 SAX
解析器不断的内存。缺点是您无法获得将整个 DOM 存储在内存中的流畅 API,并且如果您想在嵌套节点中执行复杂的回调逻辑,可见性非常有限。
如果您感兴趣的只是解析特定节点和节点系列而不是解析整个 XML,那么有一个更好的解决方案可以让您兼顾两者世界和一直blogged about和 open-sourced .它基本上是 SAX 解析器之上的一个非常轻的包装器,您可以在其中注册您感兴趣的 XML 元素,并且当您获得回调时,您可以随意使用它们对应的部分 DOM 到 XPath。
通过这种方式,您可以在恒定时间保持复杂性(如上述博客中所述,扩展到超过 1GB 的 XML 文件),同时保持 XPath 对您感兴趣的 XML 元素的 DOM 的流畅性。
关于Java解析大型XML文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23276471/