Ich habe XML seit Jahren so analysiert, und ich muss zugeben, wenn die Anzahl der verschiedenen Elemente größer wird, finde ich es ein bisschen langweilig und anstrengend zu tun, hier ist was ich meine, Beispiel dummy XML:
%Vor%Dies ist ein relevanter Teil (mit Saxophon):
%Vor%Ich frage mich, ob es einen Weg gibt, diese abscheulichen Booleans loszuwerden, die mit der Anzahl der Elemente weiter wachsen. Es muss einen besseren Weg geben, dieses relativ einfache XML zu parsen. Nur indem ich die Codezeilen suche, die für diese Aufgabe notwendig sind, sieht es hässlich aus.
Momentan verwende ich SAX Parser, aber ich bin offen für alle anderen Vorschläge (außer DOM, ich kann mir nicht leisten, in Speicherparsern habe ich riesige XML-Dateien).
Hier ist ein Beispiel für die Verwendung von JAXB mit StAX.
Eingabedokument:
%Vor%Person.java:
%Vor%Adresse.java:
%Vor%PersonlistProcessor.java:
%Vor%Wenn Sie die XML-Definition steuern, können Sie ein XML-Bindungswerkzeug verwenden, zum Beispiel JAXB (Java-Architektur für XML-Bindung). In JAXB können Sie ein Schema für die XML-Struktur definieren ( XSD und andere werden unterstützt) oder kommentieren Sie Ihre Java-Klassen, um die Serialisierungsregeln zu definieren. Sobald Sie eine eindeutige deklarative Zuordnung zwischen XML und Java haben, wird das Marshalling und das Unmarshalling von / nach XML trivial.
Die Verwendung von JAXB erfordert mehr Speicher als SAX-Handler, aber es gibt Methoden, um die XML-Dokumente nach Teilen zu verarbeiten: Umgang mit großen Dokumente .
Ich habe xsteam verwendet, um meine eigenen Objekte zu xml zu serialisieren und sie dann als Java-Objekte zurück zu laden. Wenn Sie alles als POJOs darstellen können und Sie die POJOs richtig mit den Typen in Ihrer XML-Datei annotieren, können Sie es möglicherweise viel einfacher verwenden.
Wenn eine Zeichenfolge ein Objekt in XML darstellt, können Sie einfach Folgendes schreiben:
Order theOrder = (Order)xstream.fromXML(xmlString);
Ich habe es immer verwendet, um ein Objekt in einer Zeile in den Speicher zu laden, aber wenn Sie es streamen und verarbeiten müssen, sollten Sie in der Lage sein, ein HierarchicalStreamReader um das Dokument zu durchlaufen. Dies könnte sehr ähnlich zu Simple sein, vorgeschlagen von @Dave.
In SAX "pusht" der Parser die Ereignisse bei Ihrem Handler, also müssen Sie den gesamten Housekeeping durchführen, wie Sie es hier gewohnt sind. Eine Alternative wäre StAX (das Paket javax.xml.stream
), das immer noch streamt, aber Ihr Code ist verantwortlich für das "Ziehen" von Ereignissen aus dem Parser. Auf diese Weise wird die Logik, welche Elemente in welcher Reihenfolge erwartet werden, im Kontrollfluss Ihres Programms kodiert und muss nicht explizit in boolescher Form dargestellt werden.
Abhängig von der genauen Struktur des XML kann es einen "Mittelweg" geben, der ein Toolkit wie XOM verwendet, das eine Funktionsweise hat, wo Sie parsen einen Teilbaum des Dokuments in ein DOM-ähnliches Objektmodell, verarbeiten diesen Zweig, werfen ihn weg und parsen den nächsten. Dies ist gut für repetitive Dokumente mit vielen ähnlichen Elementen, die jeweils isoliert verarbeitet werden können - Sie erhalten die Leichtigkeit der Programmierung zu einer Baum-basierten API innerhalb jedes Zweiges, haben aber dennoch das Streaming-Verhalten, mit dem Sie große Dokumente effizient analysieren können.
> %Vor% Sie können eine ähnliche Sache mit einer Kombination aus StAX und JAXB erreichen - JAXB-Klassen mit Annotationen definieren, die Ihr sich wiederholendes Element darstellen (Element in diesem Beispiel) und dann einen StAX-Parser erstellen, zum ersten Item
start-Tag navigieren und Dann können Sie einen vollständigen Item
gleichzeitig aus dem XMLStreamReader
entfernen.
Wie andere vorgeschlagen haben, wäre ein Stax-Modell ein besserer Ansatz, um den Speicherfußdruck zu minimieren, da es sich um ein Push-basiertes Modell handelt. Ich habe persönlich Axio verwendet (was in Apache Axis verwendet wird) und Elemente mit XPath-Ausdrücken analysieren, die weniger ausführlich sind als Knotenelemente durchzugehen, wie Sie es im Code-Snippet getan haben.
Ich habe diese Bibliothek benutzt. Es sitzt auf der Standard-Java-Bibliothek und erleichtert mir die Dinge. Insbesondere können Sie nach einem bestimmten Element oder Attribut anhand des Namens fragen, anstatt die große "if" -Anweisung zu verwenden, die Sie beschrieben haben.
Es gibt eine andere Bibliothek, die kompakteres XML-Parsing, RTXML, unterstützt. Die Bibliothek und ihre Dokumentation befinden sich auf rasmusforkel.com . Ich habe das Parsen der Datei in der ursprünglichen Frage implementiert und füge das komplette Programm hier ein:
%Vor%Sie werden feststellen, dass die Suchfunktionen in N, E oder D enden. Sie beziehen sich darauf, was zu tun ist, wenn das gewünschte Datenelement nicht vorhanden ist. N steht für Return Null, E steht für Throw Exception und D steht für Default.
Lösung ohne externes Paket oder XPath: verwenden Sie enum
"PARSE_MODE", wahrscheinlich in Kombination mit Stack<PARSE_MODE>
:
1) Die grundlegende Lösung:
a) Felder
%Vor% b) Mach dein List<String>
, vielleicht im Konstruktor:
c) startElement
und endElement
:
... was bedeutet das alles? Zu jeder Zeit haben Sie Kenntnisse über den "Parse-Modus", in dem Sie sich befinden ... und Sie können auch Stack<PARSE_MODE> modeBreadcrumbs
betrachten, wenn Sie herausfinden müssen, welche anderen Parsing-Modi Sie hier durchlaufen haben ...
Ihre Methode characters
wird dann wesentlich sauberer:
2) Die "professionellere" Lösung:
abstract
klasse, welche konkreten Klassen erweitert werden müssen und welche dann keine Möglichkeit haben, Stack
usw. zu ändern qName
anstatt localName
. Also:
Dann der hervorstechende Teil der konkreten Unterklasse:
%Vor% PS Dies ist ein Ausgangspunkt für anspruchsvollere Dinge: Sie könnten zum Beispiel ein List<Object>
einrichten, das mit dem Stack<PARSE_MODE>
synchronisiert bleibt: das Objects
könnte dann alles sein, was Sie wollen, damit Sie " greifen Sie "in den aufsteigenden" XML-Knoten "desjenigen ein, mit dem Sie es zu tun haben. Verwenden Sie jedoch kein Map
: Das Stack
kann möglicherweise dasselbe PARSE_MODE
-Objekt mehr als einmal enthalten. Dies veranschaulicht ein grundlegendes Merkmal aller baumartigen Strukturen: kein einzelner Knoten (hier: Parse-Modus) existiert isoliert: seine Identität wird immer durch den gesamten Pfad definiert, der zu ihm führt .