Java解析大型XML文档

时间:2014-04-24 18:02:58

标签: java xml

我试图解析并替换大型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的时间打破较小的块,那么需要10秒左右。对于解析此文档的方式,是否存在效率低下的问题?

---- ---- EDIT

基于对此的评论和答案,我转而使用Sax和XmlStreamWriter。这里的参考/示例:http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/

转向使用SAX后,replaceData函数的内存使用量不会扩展到XML文件的大小,XML文件处理时间平均会达到~18秒。

2 个答案:

答案 0 :(得分:3)

正如人们在评论中提到的那样将整个DOM加载到内存中,尤其是对于大型XML而言,效率非常低,因此更好的方法是使用消耗常量内存的SAX解析器。缺点是你不能获得流畅的API,将整个DOM放在内存中,如果你想在嵌套节点中执行复杂的回调逻辑,那么可见性是非常有限的。

如果您有兴趣做的是 解析特定节点和节点系列而不是解析整个XML ,那么有一个更好的解决方案可以让您最好地解决这两个问题世界已经blogged aboutopen-sourced。它基本上是SAX解析器顶部的一个非常轻的包装器,您可以在其中注册您感兴趣的XML元素,当您获得回调时,您可以使用相应的部分DOM到XPath。

通过这种方式,您可以将复杂性保持在恒定时间(如上文博客中所述,扩展到超过1GB的XML文件),同时保持XPath-ing您感兴趣的XML元素的DOM的流畅性。

答案 1 :(得分:2)

当XSLT专为此任务而设计时,为什么要在Java中执行此操作?

45Mb是一个容纳在内存中的大文件,但仍然可行。良好的XSLT处理器(如Saxon)使用的树模型(通常在搜索速度的存储空间中)比通用DOM(例如,因为它们是只读的)更有效。 XSLT还有更多优化代码的范围。

我无法从您的代码中反向设计您的规范,但我没有在您的描述中看到本质上非线性的内容。我没有看到为什么撒克逊人需要花费超过10分钟的时间。