2013-02-28 12 views
11

Mam następujący problem:analizowania składni dokumentów XML w Javie duży

Mam plik XML (około 1GB), i iteracyjne w górę iw dół (czyli nie sekwencyjna, jedno po drugim) w celu aby uzyskać wymagane dane i wykonać na nich pewne operacje. Początkowo korzystałem z pakietu DOM Java, ale oczywiście podczas analizowania pliku XML JVM osiąga maksymalny obszar sterty i jest zatrzymywany.

Aby rozwiązać ten problem, jednym z rozwiązań, które wymyśliłem, było znalezienie innego parsera, który iteruje każdy element w pliku XML, a następnie zapisuję jego zawartość w tymczasowej bazie danych SQLite na dysku twardym. Dlatego w ten sposób sterty JVM nie są przekraczane, a gdy wszystkie dane zostaną wypełnione, ignoruję plik XML i kontynuuję operacje na tymczasowej bazie danych SQLite.

Czy istnieje inny sposób, w jaki mogę rozwiązać mój problem?

+1

użyj jaxb do parsowania xml – Biswajit

+1

Tak jak inni mówili, że musisz użyć parsera SAX zamiast parsera DOM, zrobi dokładnie to, czego potrzebujesz. Przeczytaj to: http://stackoverflow.com/questions/6828703/difference-about-sax-and-dom – cowls

+0

Jeśli nie możesz zatrzymać całego drzewa DOM, musisz znaleźć sposób na wykonanie przetwarzania sekwencyjnie. Czy to jest możliwe? Czy możesz pokazać XSLT, który robi to, czego potrzebujesz? –

Odpowiedz

12

SAX (Simple API for XML) pomoże ci tutaj.

przeciwieństwie parsera DOM, parser SAX nie stworzyć reprezentację w pamięci dokumentu XML i tak jest szybciej i zużywa mniej pamięć. Zamiast tego analizator składni SAX informuje klientów o strukturze dokumentu XML o strukturze , wywołując wywołania zwrotne, tzn. Wywołując metody w instancji org.xml.sax.helpers.DefaultHandler dostarczonej do analizatora składni.

Oto przykład realizacja:

SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); 
DefaultHandler handler = new MyHandler(); 
parser.parse("file.xml", handler); 

Gdzie w MyHandler zdefiniować działania, które należy podjąć, gdy zdarzenia takie jak start/koniec dokumentu/elementu są generowane.

class MyHandler extends DefaultHandler { 

    @Override 
    public void startDocument() throws SAXException { 
    } 

    @Override 
    public void endDocument() throws SAXException { 
    } 

    @Override 
    public void startElement(String uri, String localName, String qName, 
      Attributes attributes) throws SAXException { 
    } 

    @Override 
    public void endElement(String uri, String localName, String qName) 
      throws SAXException { 
    } 

    // To take specific actions for each chunk of character data (such as 
    // adding the data to a node or buffer, or printing it to a file). 
    @Override 
    public void characters(char ch[], int start, int length) 
      throws SAXException { 
    } 

} 
+2

Jeśli kiedykolwiek robiłeś parsowanie SAX, prawdopodobnie wiesz, że metoda 'characters()' jest również bardzo ważna i musisz wykonać ** buforowanie ** danych znakowych, ponieważ nie ma gwarancji, że dane zawartości są obsługiwane w jednym bloku (tzn. dwa wywołania 'character()' mogą być wykonane natychmiast). Myślę, że warto o tym wspomnieć. – gaborsch

+1

Nie miałem na myśli, że moje rozwiązanie jest kompletne. To była tylko elementarna realizacja. Dzięki za wskazanie. Zaktualizuję moją odpowiedź. –

+0

Dobrze, dzięki, to jest +1 – gaborsch

3

Jeśli nie chcesz być związany granicami pamięci , z pewnością polecam do korzystania z obecnego podejścia i przechowywać wszystko w bazie danych.

Parsowanie pliku XML powinno być wykonane przez SAX parser, jak każdy poleca (w tym mnie). W ten sposób możesz utworzyć jeden obiekt naraz i możesz od razu zachować go w bazie danych.

Do przetwarzania końcowego (rozwiązywanie odsyłaczy) można użyć SELECT s z bazy danych, utworzyć klucze podstawowe, indeksy itd. Można również użyć ORM (Eclipselink, Hibernate), jeśli czujesz się z tym komfortowo. .

Właściwie nie polecam SQLite, łatwiej jest skonfigurować serwer MySQL i przechowywać tam dane. Później możesz ponownie użyć danych XML (jeśli nie usuniesz).

+0

Zastanawiam się, jak ktoś może uwierzyć, że łatwiej jest skonfigurować cały serwer bazy danych, zamiast korzystać z wbudowanej bazy danych, w której wystarczy tylko dołączyć plik JAR, aby niczego nie instalować. Myślę, że w tym przypadku oddzielny serwer bazy danych byłby przesadą. Może istnieją inne dobre powody, aby korzystać z serwera baz danych, ale łatwiejsze do skonfigurowania? Naprawdę? – vanje

+0

@vanje Nie miałem na myśli Oracle :) mówimy o MySQL. Poważnie, nie mogę uwierzyć, że każdy programista miałby problem z skonfigurowaniem serwera MySQL. – gaborsch

+0

Myślę, że każdy programista powinien być w stanie wykonać podstawową instalację zarówno Oracle, jak i MySQL. Zgadzam się z tobą, że Oracle jest dużo bardziej skomplikowany niż MySQL. Ale nie o to chodzi. Porównano MySQL z SQLite i stwierdzono, że MySQL będzie łatwiejszy w konfiguracji. Ale nie wspomniałeś o tym, co jest łatwiejsze w twojej opinii. – vanje

1

Jeśli chcesz użyć podejścia wyższego poziomu niż SAX, co może być trudne do zaprogramowania, możesz przyjrzeć się strumieniowym transformacjom XSLT za pomocą niedawnego wydania Saxon-EE. Jednak byłeś zbyt niejasny odnośnie dokładnego przetwarzania, które robisz, aby wiedzieć, czy to zadziała w twoim przypadku.

0

jeśli wymagają zasobów przyjazne podejście do obsługi bardzo dużych xml spróbuj tego: http://www.xml2java.net/xml-to-java-data-binding-for-big-data/ pozwala na przetwarzanie danych w sposób SAX, ale z przewagą coraz imprez na wysokim poziomie (dane xml odwzorowywane na Javie) i możliwość bezpośredniego działania z tymi obiektami w kodzie.więc łączy wygodę jaxb i przyjazność dla zasobów SAX.

Powiązane problemy