Как изменить огромный 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