2013-05-10 10 views
7

Mam ogromny XML (~ 2 GB) i muszę dodać nowe elementy i zmodyfikować stare. Na przykład mam:Jak zmodyfikować ogromny plik XML przez StAX?

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

i chcesz uzyskać:

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

Użyłem poniższy kod:

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

Ale wynik był następujący:

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

Jakieś pomysły?

+0

Jeśli masz wystarczająco dużo pamięci, vtd-xml to opcja, która oferuje drastycznie prostsze kodowanie ... podczas gdy zajmuje o 50% więcej pamięci i zachowuje wszystko w pamięci, nie wysadza się jak DOM http://sdiwc.us/digitlib/journal_paper.php?paper=00000582.pdf –

Odpowiedz

17

Spróbuj tego

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

Uwagi

nowy FileWriter (plik, true) jest dodanie na końcu pliku, trudno naprawdę potrzebne

equalsIgnoreCase („książki”) jest zły pomysł, ponieważ XML jest rozróżniana

+0

Niestety, ten kod nie działa. NetBeans daje mi błąd: 'Przyczyna: javax.xml.stream.XMLStreamException: ParseError w [wiersz, col]: [4,2] Wiadomość: Struktury dokumentu XML muszą zaczynać się i kończyć w obrębie tej samej jednostki. \t w com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next (XMLStreamReaderImpl.java:598) \t w com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent (XMLEventReaderImpl.java:83) \t na librarian.controllers.BookCardController.saveToXML (BookCardController.java:140) \t ... więcej 54” A ponadto usuwa całą zawartość pliku ... – Eugene

+0

co jest wyjątek? Przetestowałem to z twoim xml przed wysłaniem –

+0

Właśnie wypróbowałem to. I znowu ten sam wyjątek: 'Przyczyna: javax.xml.stream.XMLStreamException: ParseError w [wiersz, col]: [3,5] Wiadomość: struktury dokumentów XML muszą zaczynać się i kończyć w obrębie tego samego obiektu. \t w com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next (XMLStreamReaderImpl.java:598) \t w com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent (XMLEventReaderImpl.java:83) \t na librarian.controllers.BookCardController.saveToXML (BookCardController.java:138) \t ... więcej 54” ja naprawdę nie wiem, dlaczego, ale dodatkowo ten kod kasuje mój plik. – Eugene

3

Jasne jest, dlaczego zachowuje się tak, jak to robi. To, co aktualnie robisz, to otwieranie istniejącego pliku w trybie dodawania wyjść i zapisywanie elementów na końcu. To wyraźnie przeczy temu, co próbujesz zrobić.

(Poza tym: jestem zaskoczony, że działa tak dobrze, jak to ma miejsce, ponieważ strona wejściowa prawdopodobnie zobaczy elementy, które strona wyjściowa zostanie dodana do końca pliku, a tak naprawdę wyjątki, takie jak Evgeniy Dorofeev's przykład daje takie rzeczy, których się spodziewałam. Problem polega na tym, że jeśli spróbujesz odczytać i napisać plik tekstowy w tym samym czasie, a czytnik lub program piszący używa jakiejkolwiek formy buforowania jawnego lub niejawnego, czytnik jest można zobaczyć stany częściowe.)

Aby to naprawić, zacznij od przeczytania jednego pliku i zapisania do innego pliku. Appending nie zadziała. Następnie musisz ustalić, że elementy, atrybuty, zawartość itp., Które są odczytywane z pliku wejściowego, to skopiowane do pliku wyjściowego. Na koniec musisz dodać dodatkowe elementy w odpowiednich punktach.


And is there any possibility to open the XML file in mode like RandomAccessFile, but write in it by StAX methods?

No. To jest teoretycznie niemożliwe. Aby móc poruszać się po strukturze plików XML w "losowym" pliku, najpierw musisz przeanalizować całą sprawę i zbudować indeks wszystkich elementów. Nawet jeśli to zrobisz, kod XML jest nadal przechowywany jako znaki w pliku, a dostęp losowy nie pozwala na wstawianie i usuwanie znaków w środku pliku.

Być może najlepszym rozwiązaniem byłoby połączenie XSL i parsera stylu SAX; na przykład coś na wzór tego artykułu IBM: http://ibm.com/developerworks/xml/library/x-tiptrax

+0

Czy istnieje możliwość otwarcia pliku XML w trybie takim jak RandomAccessFile, ale wpisujesz w nim metody StAX? – Eugene

+0

Jest to teoretycznie możliwe ... Chyba ... ale nie jestem świadomy żadnego gotowego rozwiązania, które jest tym, czego potrzebujesz. –

Powiązane problemy