2014-04-24 136 views
2

我试图解析,并在大型xml文件中替换值,每个大小为〜45MB。我这样做的方法是:Java解析大型XML文档

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循环需要的条件,并进行了平均10万级节点的需要2个多小时,而如果我只是打破了小长大约1k的大块,它会花费大约10秒。是否有这样的文件被解析的方式效率低下?

---- ----编辑

基于意见和回答这个问题,我切换到使用SAX和XmlStreamWriter。参考/例如:http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/

在转移到使用SAX之后,replaceData函数的内存使用量不会扩展为XML文件的大小,并且XML文件处理时间平均达到了大约18秒。

+0

'dimensionValue'从哪里来的?它去哪里?与“尺寸”一样。 –

+0

对不起,忘了编辑,当我简单的代码。这些值是数组(int [])查找。 – Niru

+0

如果我有类似的问题,我使用一个简单的方法:我让代码运行在调试器中,并经常随机停止它。最经常停靠的地方是最慢的地方。非常简单,非常高效。玩的开心。 –

回答

3

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

如果你是有趣在做的是解析特定的节点和节点的家庭,而不是解析整个XML然后有一个更好的解决方案,让您两全其美的,并一直blogged aboutopen-sourced。它基本上是SAX解析器之上的一个非常简单的包装器,您可以在其中注册您感兴趣的XML元素,以及何时获取回调函数,以便您将相应的部分DOM用于XPath。

通过这种方式,您可以在保持XPath-XML DOM元素感兴趣的同时保持您的复杂性(在上述博客文档中扩展至超过1GB的XML文件)。

+0

谢谢,我转而使用SAX和XmlStreamWriter,使用这里的示例:http://www.mkyong.com/java /如何阅读-XML的文件中的Java-SAX解析器/。对于同一组数据,读取/替换/写入现在降至18秒。 – Niru

2

为什么在XSLT被设计用于这项任务时,你是用Java来做这件事的?

45Mb是一个很大的文件在内存中,但仍然可行。优秀的XSLT处理器(如Saxon)使用的树模型比通用DOM(例如因为它们是只读的)效率更高(无论是在存储空间还是搜索速度方面)。而且XSLT有更多的空间来优化你的代码。

我无法从您的代码中反向设计您的规范,但在您的描述中没有看到任何内在非线性的内容。我没有看到任何理由,为什么在撒克逊这需要超过10分钟左右。