Besseren Weg, um xml zu Parsen
Ich habe Parsen von XML, wie dies seit Jahren, und ich muss zugeben, wenn die Anzahl der verschiedenen element wird größer, ich finde es ein bisschen langweilig und anstrengend zu tun, hier ist, was ich meine, Beispiel-dummy-XML:
<?xml version="1.0"?>
<Order>
<Date>2003/07/04</Date>
<CustomerId>123</CustomerId>
<CustomerName>Acme Alpha</CustomerName>
<Item>
<ItemId> 987</ItemId>
<ItemName>Coupler</ItemName>
<Quantity>5</Quantity>
</Item>
<Item>
<ItemId>654</ItemId>
<ItemName>Connector</ItemName>
<Quantity unit="12">3</Quantity>
</Item>
<Item>
<ItemId>579</ItemId>
<ItemName>Clasp</ItemName>
<Quantity>1</Quantity>
</Item>
</Order>
Dies ist ein relevanter Teil (mit sax) :
public class SaxParser extends DefaultHandler {
boolean isItem = false;
boolean isOrder = false;
boolean isDate = false;
boolean isCustomerId = false;
private Order order;
private Item item;
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
if (localName.equalsIgnoreCase("ORDER")) {
order = new Order();
}
if (localName.equalsIgnoreCase("DATE")) {
isDate = true;
}
if (localName.equalsIgnoreCase("CUSTOMERID")) {
isCustomerId = true;
}
if (localName.equalsIgnoreCase("ITEM")) {
isItem = true;
}
}
public void characters(char ch[], int start, int length) throws SAXException {
if (isDate){
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
String value = new String(ch, start, length);
try {
order.setDate(formatter.parse(value));
} catch (ParseException e) {
e.printStackTrace();
}
}
if(isCustomerId){
order.setCustomerId(Integer.valueOf(new String(ch, start, length)));
}
if (isItem) {
item = new Item();
isItem = false;
}
}
}
Frage ich mich, gibt es einen Weg, um loszuwerden, diese hässlichen booleans, die wächst mit der Anzahl der Elemente. Es muss einen besseren Weg, um zu analysieren, in diesem relativ einfachen xml. Einfach durch einen Blick in den code-Zeilen notwendig, um diese Aufgabe sieht häßlich aus.
Derzeit bin ich mit SAX-parser, aber ich bin offen für andere Vorschläge (außer DOM, ich kann nicht leisten, in-memory-Parser habe ich riesige XML-Dateien).
- Sie könnten versuchen, StAX
- Wenn Sie einen Konzert-Daten-Modell, dass die Erzeugung der XML-würde ich werfen Sie einen Blick auf XStream (xstream.codehaus.org). Es macht einen wirklich netten job der Serialisierung von Daten in xml und zurück.
- Zum Thema, ich mag beginnend mit XSDs und mithilfe von XmlBeans. Leicht OT, XML-tags sollen die groß-und Kleinschreibung und diesen code bricht, die.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist ein Beispiel der Verwendung von JAXB mit StAX.
Input-Dokument:
Person.java:
Address.java:
PersonlistProcessor.java:
Wenn Sie die Kontrolle der definition von XML, man könnte eine XML-binding-tool, zum Beispiel JAXB (Java Architecture for XML Binding.) In JAXB definieren Sie ein schema für die XML-Struktur (XSD und andere werden unterstützt) oder kommentieren Sie Ihren Java-Klassen zur Definition der Serialisierung Regeln. Sobald Sie haben eine klare deklarative Zuordnung zwischen XML und Java, marshalling und unmarshalling zu/von XML-banal.
Mithilfe von JAXB benötigt mehr Speicher als SAX-Handler, aber es existieren Methoden zum verarbeiten der XML-Dokumente, die von teilen: Umgang mit großen Dokumenten.
JAXB-Seite von Oracle
Habe ich mit xsteam zu serialisieren meine eigenen Objekte in xml und dann laden Sie Sie zurück, als Java-Objekte. Wenn Sie darstellen können, everythign als POJOs und Sie richtig kommentieren die POJOs zu entsprechen, die Typen in der xml-Datei, die Sie vielleicht finden es viel einfacher zu bedienen.
Wenn ein String repräsentiert ein Objekt in XML, können Sie einfach schreiben:
Order theOrder = (Order)xstream.fromXML(xmlString);
Habe ich immer benutzt, um ein Objekt geladen in den Speicher in einer einzigen Zeile, aber wenn Sie benötigen, zu streamen und zu verarbeiten, wie Sie gehen Sie sollten in der Lage sein zu verwenden HierarchicalStreamReader zu Durchlaufen und die document. Dies könnte sehr ähnlich Einfache, vorgeschlagen von @Dave.
In der SAX-parser "schiebt" Ereignisse auf Ihrem handler, so müssen Sie alles tun, die Hauswirtschaft, die Sie hier. Eine alternative wäre StAX (die
javax.xml.stream
- Paket), das ist immer noch das streaming, aber dein code ist verantwortlich für das "ziehen" Ereignisse aus dem parser. Auf diese Weise die Logik, welche Elemente erwartet werden, in welcher Reihenfolge codiert, in der Ablaufsteuerung des Programms, anstatt Sie explizit repräsentiert Boolesche Werte.Je nach der genauen Struktur der XML-möglicherweise gibt es einen "mittleren Weg" mithilfe eines Toolkits wie XOM, die eine Betriebsart, wo Sie analysiert eine Unterstruktur, die das Dokument in ein DOM-ähnliches Objekt, Modell, Prozess, Zweig, dann werfen Sie es Weg, und analysieren Sie die nächste. Das ist gut für wiederkehrende Dokumente, die viele ähnliche Elemente, die jeweils verarbeitet werden, in die isolation, bekommen Sie die Leichtigkeit der Programmierung, um eine Baum-basierte API in jedem Zweig, aber immer noch das streaming-Verhalten, mit der Sie analysieren große Dokumente effizient.
Können Sie erreichen eine ähnliche Sache mit einer Kombination von StAX und JAXB - definieren JAXB annotierte Klassen, die auf die sich wiederholenden element (Element, in diesem Beispiel) und erstellen Sie dann einen StAX-parser, navigieren Sie zu dem ersten
Item
start-tag, und dann können Sie unmarshal eine kompletteItem
in einer Zeit, von derXMLStreamReader
.Als andere vorgeschlagen, ein Stax-Modell wäre ein besserer Ansatz zur Minimierung der Speicher-Fuß drucken, da es eine push-basierte Modell. Ich habe persönlich verwendet Axio (Welches in Apache Axis) und analysieren Sie Elemente mithilfe von XPath-Ausdrücken, die weniger ausführlich, als sich durch Knoten-Elemente, wie Sie getan haben, in den code-snippet zur Verfügung gestellt.
Habe ich mit dieser Bibliothek. Es sitzt oben auf der standard-Java-Bibliothek und macht die Dinge einfacher für mich. Insbesondere können Sie Fragen für ein bestimmtes element oder Attribut durch den Namen, anstatt das große "wenn" - Anweisung, die Sie beschrieben haben.
http://marketmovers.blogspot.com/2014/02/the-easy-way-to-read-xml-in-java.html
Gibt es eine weitere Bibliothek, die unterstützt kompaktere XML-parsing, RTXML. Die Bibliothek und Dokumentation ist auf rasmustorkel.com. Ich habe implementiert die das Parsen der Datei in der ursprünglichen Frage, und ich bin mit dem gesamten Programm finden Sie hier:
Werden Sie feststellen, dass die retrieval-Funktionen enden in N -, E-oder D. Sie verweisen auf das, was zu tun ist, wenn das gewünschte Datenelement nicht vorhanden. N steht für Null zurückgegeben, E steht für Ausnahme auslösen, und D steht für die Standardeinstellungen verwenden.
Lösung ohne Verwendung von außerhalb des Pakets, oder auch XPath: verwenden Sie ein
enum
"PARSE_MODE", vermutlich in Kombination mit einemStack<PARSE_MODE>
:1) Die einfache Lösung:
a) Felder
b) machen Sie Ihren
List<String>
vielleicht im Konstruktor:c)
startElement
undendElement
:... also, was bedeutet all dies? Zu jeder Zeit haben Sie Kenntnisse in der "parse-Modus" sind Sie in ... und Sie können auch einen Blick auf die
Stack<PARSE_MODE> modeBreadcrumbs
wenn Sie brauchen, um herauszufinden, was andere parse-Modi, die Sie Durchlaufen, um hier zu bekommen...Ihre
characters
Methode wird dann wesentlich cleaner:2) Die "professionelleren" Lösung:
abstract
- Klasse, die konkreten Klassen zu erweitern, und die haben dann keine Möglichkeit zum ändern derStack
usw. NB: dieses untersuchtqName
eher alslocalName
. Also:Dann, markanten Teil konkrete Unterklasse:
PS dies ist ein Ausgangspunkt für kompliziertere Sachen: zum Beispiel, Sie könnte einen
List<Object>
ist gehalten, die synchronisiert mit derStack<PARSE_MODE>
: dieObjects
könnte dann alles, was Sie wollen, sodass Sie im "reach-back" in der Aszendent "den XML-Knoten", das Sie zu tun haben. Nicht mit einemMap
aber: dieStack
können möglicherweise enthalten die gleichenPARSE_MODE
Objekt mehr als einmal. Diese in der Tat zeigt ein grundlegendes Merkmal aller Baum-ähnlichen Strukturen: keine einzelnen Knoten (hier: parse-Modus) existiert in isolation: seine Identität ist immer definiert durch den gesamten Pfad zu ihm führenden.}