Große XML Dateien mit PHP verarbeiten

Ich musste diese Woche eine knapp 50 MB große XML Datei (etwa 70.000 Items) einlesen, die Elemente neu zusammenstellen und in verschiedene Dateien neu abspeichern. Die XML Datei enthielt Daten aus einem SAP System und die Struktur sah im Grunde ganz einfach aus:

screenshot sap-xml

Diese Struktur ist anscheinend ein Standard Export Format von SAP, wenn man nach den XML Tags im Netzt sucht, findet man schnell Entwickler die auf die gleichen Probleme mit der Struktur wie ich gestossen sind.

Im ersten Versuch, habe ich das PHP SimpleXML Objekt versucht und musste ganz schnell festellen, dass die Verarbeitung einer so großen XML Datei ewig dauert. Besonders langsam wird es wenn man mit Sorts und Unique Methoden versucht die Daten neu zu strukturieren. Also bin ich im zweiten Versuch auf mit dem PHP XMLReader Objekt rangegangen und das war schon wesentlich performanter. Leider ist das Durchgehen der einzelnen Knoten mit dem XML Reader echt zickig. Man findet zwar jede menge Hilfestellungen im Netz, aber so richtig gut hat das ganze nicht funktioniert.

Schlußendlich hab ich dann die PHP DOM Variante ausprobiert und das hat dann wunderbar geklappt. Das tolle am PHP DOM ist, dass die XML Struktur automatisch in ein Objekt konvertiert wird und man dann wieder so praktische Schleifen Funktionen  wie Foreach verwenden kann. Noch besser ist, dass man XPath verwenden kann um sehr schnelle abfragen auf die riesige XML Struktur absetzen kann.

Man muss immer zu erst ein DOMDocument erschaffen und gleich die Leerzeichen mit preserveWhiteSpace eleminieren. Dann geht man her und läd die XML Datei in das DOMDocument. Wenn man nun XPath verwenden möchte, muss man ein DOMXPath Objekt erstelle und die gewünschte XPath-Query definieren. Nachdem Absenden der XPath Query erhält man ein NodeList Objekt zurück, in dem das Ergebnis der XPath Abfrage enthalten ist. Diese kann man dann wieder mit einer Foreach-Schleife durchgehen und einzelne Elemente der XML Struktur verarbeiten.

Im Grunde sieht der Code-Schnippsel so aus:

/* creating the DomDocument and set it clean */
$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;

/* loading the file */
$dom->Load('Path-To-Xml-File');

/* preparing the xpath for the dom doc */
$xpath = new DOMXPath($dom);

/* query just the attributes from the xml document */
$query = '//item';
$items = $xpath->query($query);

/* going thru each item */
foreach ($items as $item) {        
        
    echo "ITEM: ".$item->nodeValue;
}

Die Verarbeitung aller Knoten in der XML Datei, inklusive etwas anderer Programmlogik, dauert trotzdem noch knapp zwei Stunden. Als Verlgeich hab ich das Programm auch noch mal in Powershell  programmiert und das war noch enttäuschender. Mit Powershell läuft die Verarbeitung knapp 6 Stunden. War für mich etwas überraschend, das PHP im Vergleich zu Powershell im Bezug XML Daten, wesentlich schneller ist. Und ich hab noch nicht mal angefangen mit dem Tuning, ich bin mir sicher, dass ich das Programm (in PHP) noch etwas schneller gestaltet bekomme.

*UPDATE* Als schnellste Variante hat sich am ende doch XSLT herausgestellt. Hiermit konnte ich die Sortierung und Formatierung der Ausgabe in einem Aufwasch gestalten. Das hat die Performance erheblich gesteigert. Alles in Allem dauert es jetzt nur noch etwa 2 Min 20 um alles abzuarbeiten. Ich habe das ganze ein einen eigenen Artikel zusammengefasst.

http://www.agile-coding.net/grosse-xml-dateien-mit-php-verarbeiten/