如何通过StAX修改巨大的XML文件?

时间:2013-05-10 09:49:22

标签: java xml xml-parsing stax

我有一个巨大的XML(~2GB),我需要添加新元素并修改旧元素。例如,我有:

<books>
    <book>....</book>
    ...
    <book>....</book>
</books>

想得到:

<books>
   <book>
      <index></index>
      ....
   </book>
   ...
   <book>
      <index></index>
      ....
   </book>
</books>

我使用了以下代码:

XMLInputFactory inFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = inFactory.createXMLEventReader(new FileInputStream(file));
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = factory.createXMLStreamWriter(new FileWriter(file, true));
while (eventReader.hasNext()) {
   XMLEvent event = eventReader.nextEvent();
   if (event.getEventType() == XMLEvent.START_ELEMENT) {
      if (event.asStartElement().getName().toString().equalsIgnoreCase("book")) {
          writer.writeStartElement("index");
          writer.writeEndElement();
       }
    }
}
writer.close();

但结果如下:

<books>
   <book>....</book>
   ....
   <book>....</book>
</books><index></index>

有什么想法吗?

3 个答案:

答案 0 :(得分:20)

试试这个

    XMLInputFactory inFactory = XMLInputFactory.newInstance();
    XMLEventReader eventReader = inFactory.createXMLEventReader(new FileInputStream("1.xml"));
    XMLOutputFactory factory = XMLOutputFactory.newInstance();
    XMLEventWriter writer = factory.createXMLEventWriter(new FileWriter(file));
    XMLEventFactory eventFactory = XMLEventFactory.newInstance();
    while (eventReader.hasNext()) {
        XMLEvent event = eventReader.nextEvent();
        writer.add(event);
        if (event.getEventType() == XMLEvent.START_ELEMENT) {
            if (event.asStartElement().getName().toString().equalsIgnoreCase("book")) {
                writer.add(eventFactory.createStartElement("", null, "index"));
                writer.add(eventFactory.createEndElement("", null, "index"));
            }
        }
    }
    writer.close();

备注

新的FileWriter(file,true)附加到文件的末尾,你几乎不需要它

equalsIgnoreCase(“book”)是个坏主意,因为XML区分大小写

答案 1 :(得分:6)

很明显,为什么它的行为方式如此。你实际做的是在输出附加模式下打开现有文件并在结尾处写入元素。这显然与你要做的事情相矛盾。

(旁白:我很惊讶它的效果和输入端可能会看到输出端添加到文件末尾的元素一样好。确实像Evgeniy Dorofeev的例子那样例外给出了我期望的那种东西。问题是如果你试图同时读写文本文件,并且读者或作者使用任何形式的缓冲,无论是明确的还是隐含的,读者都有责任看部分状态。)

要解决此问题,您必须先从一个文件中读取并写入另一个文件。追加不起作用。然后,您必须安排从输入文件中读取的元素,属性,内容等复制到输出文件。最后,您需要在适当的位置添加额外的元素。


  

是否有可能以RandomAccessFile等模式打开XML文件,但是用StAX方法写入?

没有。这在理论上是不可能的。为了能够在“随机”文件中浏览XML文件的结构,您首先需要解析整个事物并构建所有元素所在的索引。即使你已经这样做了,XML仍然作为字符存储在文件中,并且随机访问不允许您在文件中间插入和删除字符。

也许你最好的选择是结合XSL和SAX风格的解析器;例如这篇IBM文章的内容:http://ibm.com/developerworks/xml/library/x-tiptrax

答案 2 :(得分:0)

也许JavaEE教程中的这个StAX读写示例有助于:http://docs.oracle.com/javaee/5/tutorial/doc/bnbfl.html#bnbgq

您可以在此处下载教程示例:https://java.net/projects/javaeetutorial/downloads

为了快速访问,所提到的示例如下:.htm“&gt; http://read.pudn.com/downloads79/ebook/304101/javaeetutorial5/examples/stax/readnwrite/src/readnwrite/EventProducerConsumer.java_。热媒