Как изменить огромный XML-файл StAX?

У меня огромный XML (~2 ГБ), и мне нужно добавить новые элементы и изменить старые. Например, у меня есть:

<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 ответа

Решение

Попробуй это

    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("книга") - плохая идея, потому что XML чувствителен к регистру

Ну, вполне понятно, почему он так себя ведет. На самом деле вы открываете существующий файл в режиме вывода и пишете элементы в конце. Это явно противоречит тому, что вы пытаетесь сделать.

(В сторону: я удивлен, что это работает так же хорошо, как это происходит, учитывая, что сторона ввода, вероятно, увидит элементы, которые сторона вывода добавлена ​​в конец файла. И действительно, исключения, подобные примеру Евгения Дорофеева, дают Я ожидал такого рода проблемы. Проблема в том, что если вы пытаетесь одновременно читать и записывать текстовый файл, а читатель или писатель использует любую форму буферизации, явную или неявную, читатель может увидеть частичное состояния.)

Чтобы это исправить, вы должны начать с чтения из одного файла и записи в другой файл. Добавление не будет работать. Затем вы должны организовать, чтобы элементы, атрибуты, содержимое и т. Д., Которые считываются из входного файла, копировались в выходной файл. Наконец, вам нужно добавить дополнительные элементы в соответствующих точках.


И есть ли возможность открыть файл XML в режиме, подобном RandomAccessFile, но записать в него методами StAX?

Нет. Это теоретически невозможно. Чтобы иметь возможность перемещаться по структуре XML-файла в "случайном" файле, вам сначала нужно проанализировать все это и построить индекс того, где находятся все элементы. Даже после того, как вы это сделали, XML-файл все еще сохраняется в виде символов в файле, и произвольный доступ не позволяет вставлять и удалять символы в середине файла.

Возможно, лучшим вариантом будет сочетание XSL и парсера в стиле SAX; например, что-то вроде этой статьи IBM: http://ibm.com/developerworks/xml/library/x-tiptrax

Может быть, поможет этот пример чтения и записи StAX в JavaEE: http://docs.oracle.com/javaee/5/tutorial/doc/bnbfl.html

Вы можете загрузить учебные примеры здесь: https://java.net/projects/javaeetutorial/downloads

Для быстрого доступа приведенный пример приведен здесь: .htm">http://read.pudn.com/downloads79/ebook/304101/javaeetutorial5/examples/stax/readnwrite/src/readnwrite/EventProducerConsumer.java_.htm

Другие вопросы по тегам