Freaky Friday: Simple XML Iteration

Endlich Freitag! Auch in 2020 wird es hier unregelmäßig Codeschnipsel geben, die Euch das Leben erleichtern werden. Dieses mal geht es um die einfache Iteration über XML Knoten. Während man vor Jahren noch mit überdimensionierten Bibliotheken aufwendig XML Strings versucht hat sauber zu verarbeitet, bietet PHP heute einfache, performante Möglichkeiten einfache XML Konstrukte zu parsen. Heute werfen wir einfach mal einen Blick auf die SimpleXMLIterator Klasse.

Hierzu ein einfaches Beispiel von wiederkehrenden XML Elementen, die geparst und in entsprechende Value Objekte umgewandelt werden sollen.

<?php
namespace Marcel;

use Exception;
use Iterator;
use JsonSerializable;
use SimpleXMLIterator;
use SplObjectStorage;

$xml = <<<XML
    <elements>
        <element>
            <name>Marcel</name>
            <company>MM Newmedia</company>
        </element>
        <element>
            <name>Nina</name>
            <company>Purpurorange Grafikdesign</company>
        </element>
    </elements>
XML;

Kurz erklärt: Eine Gruppe von Elementen, die jeweils den Namen einer Person und den Namen der dazugehörigen Firma beinhalten. Eine ziemlich einfache Struktur, um es für dieses Beispiel nicht zu komplex zu machen. Dazu ein Namespace und die benötigten use Statements, die im weiteren Verlauf noch wichtig werden.

Da wir die Daten aus dem XML in entsprechende JSON String Entsprechungen umwandeln möchten, benötigen wir in diesem Beispiel ein Value Objekt, welches die Daten eines XML Elements enthält.

class ElementValue implements JsonSerializable
{
    protected $name;
    
    protected $company;
    
    public function getName(): ?string
    {
        return $this->name;
    }
    
    public function setName(?string $name): self
    {
        $this->name = $name;
        return $this;
    }
    
    public function getCompany(): ?string
    {
        return $this->company;
    }
    
    public function setCompany(?string $company): self
    {
        $this->company = $company;
        return $this;
    }
    
    public function jsonSerialize(): array
    {
        return get_object_vars($this);
    }
}

Ein einfaches Value Objekt mit getter- und setter-Methoden, entsprechenden Return Type Hints und der Implementierung des JSONSerializable Interfaces, um das Objekt später als JSON Entsprechung darstellen zu können. Jetzt benötigen wir nur noch den Iterator, der über das XML iteriert.

function iterate(Iterator $iterator, SplObjectStorage $collection, ElementValue $value = null): SplObjectStorage
{
    $iterator->rewind();
    
    while ($iterator->valid()) {
        if ($iterator->hasChildren()) {
            $children = $iterator->getChildren();
            $value = new ElementValue();
            
            iterate($children, $collection, $value);
        } else {
            $value->{'set' . ucfirst($iterator->current()->getName())}($iterator->current());
        }
        
        if ($value !== null) {
            $collection->attach($value, $value->getName());
        }
        
        $iterator->next();
    }
    
    return $collection;
}

Eine einfache Funktion, die als Parameter einen Iterator, eine Collection und ein Value Objekt annimmt. Diese Funktion macht nichts anders, als rekursiv über das oben gezeigte XML zu iterieren. Handelt es sich bei dem gefundenen XML Knoten um einen Knoten mit Kindelementen, wird die Funktion nochmals für die Kindelemente aufgerufen. Dies wird so oft wiederholt, bis das entsprechende Element keinen Kindknoten mehr besitzt. Aus den gefundenen Daten wird ein Value Objekt erzeugt, welches dann mit dem Namen der Person und dem Namen der Firma bestückt wird.

Jetzt fehlt eigentlich nur noch der Funktionsaufruf. Hier kommt die eingangs erwähnte SimpleXMLIterator Klasse zum Einsatz.

try {
    $collection = new SplObjectStorage();
    $iterator = new SimpleXMLIterator($xml);
    
    $collection = iterate($iterator, $collection);
    foreach ($collection as $value) {
        var_dump(json_encode($value, JSON_PRETTY_PRINT));
    }
} catch (Exception $e) {
    var_dump($e);
}

Zunächst benötigen wir eine Collection, in der wir unsere Value Objekte ablegen können. Für die Iteration initialisieren wir die SimpleXMlIterator Klasse und geben ihr unseren XML String als Parameter mit. Die Collection wird mit dem Aufruf der iterate Methode gefüllt. Jedes Value Object in der Collection wird dann als entsprechender JSON String ausgegeben. Sofern Fehler auftreten sollten, ist das Ganze noch in einen try/catch Block eingefasst. Das Ergebnis sieht dann wie folgt aus:

{
    "name": "Marcel",
    "company": "MM Newmedia"
}
{
    "name": "Nina",
    "company": "Purpurorange Grafikdesign"
}

Fazit

Ich selbst bin nicht der größte Fan der SimpleXML Erweiterung von PHP. Wie der Name selbst schon sagt, eignet sie sich vor allem zur Verarbeitung von einfchen XML Strukturen. Für diesen Anwendungszweck ist die Erweiterung ziemlich gut aufgestellt. Für komplexere XML Strukturen arbeite ich persönlich aber bevorzugt mit der DOM Extension, da diese sehr viel mehr Möglichkeiten für den Umgang mit komplexen XML Strukturen bietet.

Wie an diesem Beispiel ersichtlich, ist die rekursive Iteration über XML mit der SimpleXMLIterator Klasse aber denkbar einfach.

Bildquelle: Image by StartupStockPhotos from Pixabay

2 Gedanken zu „Freaky Friday: Simple XML Iteration“

Kommentar verfassen

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.