【问题标题】:How to modify a huge XML file by StAX?如何通过 StAX 修改一个巨大的 XML 文件?
【发布时间】:2013-05-04 23:26:15
【问题描述】:

我有一个巨大的 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>

有什么想法吗?

【问题讨论】:

    标签: java xml xml-parsing stax


    【解决方案1】:

    试试这个

        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();
    

    注意事项

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

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

    【讨论】:

    • 不幸的是,此代码不起作用。 NetBeans 给我一个错误:'Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[4,2] 消息:XML 文档结构必须在同一个实体内开始和结束。在 com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598) 在 com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:83) 在 librarian.controllers .BookCardController.saveToXML(BookCardController.java:140) ... 54 more' 而且它会删除文件的所有内容...
    • 有什么例外?我在发布之前用你的 xml 测试了它
    • 刚刚试过。同样的异常:'引起:javax.xml.stream.XMLStreamException: ParseError at [row,col]:[3,5] 消息:XML 文档结构必须在同一个实体内开始和结束。在 com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598) 在 com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(XMLEventReaderImpl.java:83) 在 librarian.controllers .BookCardController.saveToXML(BookCardController.java:138) ... 54 更多'我真的不知道为什么,但另外这段代码会清除我的文件。
    • 嗯,这个例外似乎是因为我使用了相同的文件作为输入和输出。选择不同的目标文件后,代码开始工作,但是......输出如下:''。而且我需要将 Element 包含到现有的 XML 中。
    • 如果你只留下这个 XMLEvent event = eventReader.nextEvent(); writer.add(事件);在你应该得到输出==输入的循环中,它不能丢失,尝试调试
    【解决方案2】:

    嗯,很清楚为什么它的行为方式如此。您实际上正在做的是以输出追加模式打开现有文件并在最后写入元素。这显然与您正在尝试做的事情相矛盾。

    (旁白:考虑到输入端可能会看到输出端添加到文件末尾的元素,我很惊讶它的效果和它的效果一样好。事实上,像 Evgeniy Dorofeev 的例子这样的例外给出的是我所期望的那种事情。问题是,如果您尝试同时读取和写入文本文件,并且读取器或写入器使用任何形式的缓冲,无论是显式的还是隐式的,读者都要承担责任查看部分状态。)

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


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

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

    也许您最好的选择是将 XSL 和 SAX 样式解析器结合起来;例如类似于这篇 IBM 文章的内容:http://ibm.com/developerworks/xml/library/x-tiptrax

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2015-06-28
        • 2021-07-28
        • 2011-11-05
        • 2015-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-07
        • 1970-01-01
        相关资源
        最近更新 更多