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

Eug*_*ene 8 java xml stax xml-parsing

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

<books>
    <book>....</book>
    ...
    <book>....</book>
</books>
Run Code Online (Sandbox Code Playgroud)

并希望得到:

<books>
   <book>
      <index></index>
      ....
   </book>
   ...
   <book>
      <index></index>
      ....
   </book>
</books>
Run Code Online (Sandbox Code Playgroud)

我使用了以下代码:

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();
Run Code Online (Sandbox Code Playgroud)

但结果如下:

<books>
   <book>....</book>
   ....
   <book>....</book>
</books><index></index>
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Evg*_*eev 19

试试这个

    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();
Run Code Online (Sandbox Code Playgroud)

笔记

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

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


Ste*_*n C 5

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

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

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


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

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

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