Wie der Titel sagt, habe ich eine riesige XML-Datei (GBs)
%Vor% und ich möchte es in ein viel kleineres verwandeln, das nur ein paar Elemente enthält.
Mein Parser sollte folgendes tun:
1. Parsen Sie durch die Datei, bis ein relevantes Element beginnt.
2. Kopieren Sie das gesamte relevante Element (mit Kindern) in die Ausgabedatei. gehe zu 1.
Schritt 1 ist einfach mit SAX und unmöglich für DOM-Parser.
Schritt 2 ist nervig mit SAX, aber einfach mit dem DOM-Parser oder XSLT.
Also was? - Gibt es eine gute Möglichkeit, SAX und DOM-Parser zu kombinieren, um die Aufgabe zu erledigen?
Ja, schreibe einfach einen SAX-Content-Handler, und wenn ein bestimmtes Element gefunden wird, baust du eine Dom-Struktur für dieses Element auf. Ich habe das mit sehr großen Dateien gemacht, und es funktioniert sehr gut.
Es ist eigentlich sehr einfach: Sobald Sie auf den Anfang des gewünschten Elements stoßen, setzen Sie in Ihrem Content-Handler ein Flag, und von dort aus leiten Sie alles an den DOM-Builder weiter. Wenn Sie auf das Ende des Elements stoßen, setzen Sie das Flag auf false und schreiben das Ergebnis aus.
(Für komplexere Fälle mit verschachtelten Elementen desselben Elementnamens müssen Sie einen Stapel oder einen Zähler erstellen, aber das ist immer noch ziemlich einfach.)
StAX scheint eine offensichtliche Lösung zu sein: Es ist eher ein Pull-Parser als der "Push" von SAX oder " puffern das Ganze "Ansatz von DOM. Ich kann nicht sagen, dass ich es benutzt habe. Eine "StAX-Tutorial" -Suche kann sich als nützlich erweisen:)
Ich habe gute Erfahrungen mit STX gemacht ( Streaming-Transformationen für XML ). Im Grunde handelt es sich um eine gestreamte Version von XSLT, die sich für das Parsen großer Datenmengen mit minimalem Speicherbedarf eignet. Es hat eine Implementierung in Java namens Joost .
Es sollte einfach sein, eine STX-Transformation zu erstellen, die alle Elemente ignoriert, bis das Element mit einem bestimmten XPath übereinstimmt, dieses Element und alle untergeordneten Elemente kopiert (mit einer Identitätsvorlage innerhalb einer Vorlagengruppe) und Elemente bis zum Ende ignoriert das nächste Spiel.
AKTUALISIEREN
Ich habe eine STX-Transformation gehackt, die das tut, was ich verstehe. Dies hängt hauptsächlich von STX-only-Funktionen wie Vorlagengruppen und konfigurierbaren Standardvorlagen ab.
%Vor% Das pass-through="none"
bei stx:transform
konfiguriert die Standardvorlagen (für Knoten, Attribute usw.), um keine Ausgabe zu erzeugen, sondern untergeordnete Elemente zu verarbeiten. Dann stimmt die stx:template
mit der XPath element/child
überein (dies ist die Stelle, an der Sie Ihren Übereinstimmungsausdruck setzen), sie "verarbeitet self" in der Gruppe "copy", was bedeutet, dass die passende Vorlage von group name="copy"
aufgerufen wird aktuelles Element. Diese Gruppe hat pass-though="all"
, sodass die Standardvorlagen ihre Eingabeelemente kopieren und untergeordnete Elemente verarbeiten. Wenn das Element element/child
beendet ist, wird die Steuerung an die Vorlage zurückgegeben, die process-self
aufgerufen hat, und die folgenden Elemente werden erneut ignoriert. Bis die Vorlage wieder übereinstimmt.
Das folgende Beispiel zeigt eine Eingabedatei:
%Vor%Dies ist die entsprechende Ausgabedatei:
%Vor% Die ungewöhnliche Formatierung resultiert aus dem Überspringen der Textknoten, die Zeilenumbrüche außerhalb der child
-Elemente enthalten.
Da du über GBs sprichst, würde ich lieber die Speicherbelegung bei der Betrachtung priorisieren. SAX benötigt etwa 2-mal Speicherplatz, da das Dokument groß ist, während DOM 5-mal mindestens benötigt. Wenn Ihre XML-Datei also 1 GB groß ist, benötigt DOM mindestens 5 GB freien Speicher. Das ist nicht mehr lustig. Daher ist SAX (oder jede andere Variante wie StAX) die beste Option.
Wenn Sie den speichereffizientesten Ansatz wünschen, sehen Sie sich VTD-XML an. Es benötigt nur ein wenig mehr Speicher als die große Datei.
Schauen Sie sich StAX an, das könnte das sein, was Sie brauchen. Es gibt eine gute Einführung in IBM Developer Works .
Für solch ein großes XML-Dokument wäre etwas mit einer Streaming-Architektur wie Omnimark ideal.
Es müsste auch nichts Komplexes sein. Ein Omnimark-Skript, wie es unten steht, könnte dir das geben, was du brauchst:
%Vor%