23.8 XML_Serializer 

Besprochene Version: 0.15.0 | Lizenz: PHP-Lizenz 2.0 |
Klassendatei(en): XML/Serializer.php; XML/Deserializer.php |
Dem Paket XML_Serializer liegt eine ähnliche Idee zugrunde wie XML_Wddx. Auch XML_Serializer ist in der Lage, Daten aus Variablen zu übernehmen und sie nach XML zu konvertieren. Die so erstellte PHP-Datei kann entweder durch ein anderes Script weiterverarbeitet werden oder als Datei abgelegt werden, um später wieder eingelesen zu werden.
Um die Daten zu kodieren, ist die Methode serialize() vorgesehen, die aus einem XML_Serializer-Objekt heraus aufgerufen werden muss. Dem Konstruktor des Objekts werden die Informationen übergeben, wie der Serialisierungsvorgang durchgeführt werden soll.
require_once ('XML/Serializer.php'); // Daten, die serialisiert werden sollen $obst = array('Äpfel', 'Birnen', 'Bananen'); // Optionen fuer den Serializer $options = array ( 'addDecl' => true, 'encoding' => 'ISO-8859–1', 'indent' => ' ', 'rootName' => 'gruenzeug', 'defaultTagName' => 'obst' ); // Neues XML_Serializer-Objekt ableiten $serializer = new XML_Serializer($options); // Serialisierung durchfuehren $erg = $serializer->serialize($obst); // Fehler aufgetreten? if (true===PEAR::isError($erg)) { die($erg->getMessage()); } // Daten auslesen und ausgeben echo $serializer->getSerializedData();
Listing 23.14 Nutzung von XML_Serializer
In diesem Beispiel wird ein indiziertes Array serialisiert. Um diese Serialisierung durchzuführen, wird zunächst ein XML_Serializer-Objekt instanziiert, das mit einem Array von Optionen initialisiert wird. Dies erläutere ich ein wenig später im Text. Der Serialisierungsvorgang wird von der Methode serialize() durchgeführt, die die Daten als Parameter übergeben bekommt. Um die fertig serialisierten Daten aus dem Objekt auszulesen, ist die Methode getSerializedData() vorgesehen, die Ihnen die Daten als String zurückgibt.
Das Script aus Listing 23.14 gibt das folgende XML-Dokument aus:
<?xml version="1.0" encoding="ISO-8859–1"?> <gruenzeug> <obst>Äpfel</obst> <obst>Birnen</obst> <obst>Bananen</obst> </gruenzeug>
Wie Sie sehen, sind die Daten komplett übernommen worden. Die Informationen für die Struktur der Datei wurden aus den Optionen übernommen.
Die Deklaration der Version (<?xml... ?>) wurde eingefügt, weil die Option addDecl den Wert true übergeben bekommen hat. Die Zeichensatzinformation wurde mit dem Schlüssel encoding übergeben, und die Namen der Tags finden sich in den Schlüsseln rootName und defaultTagName. Würden die Namen hier nicht übergeben, würde das Root-Element den Datentyp wiedergeben. In diesem Fall würde es array heißen. Die Inhalte des Arrays würden alle zu Elementen vom Typ <XML_Serializer_Tag>. In Tabelle 23.3 finden Sie eine Liste aller Optionen.
[Diese Option hat zurzeit noch keine Auswirkung auf die Ausgabe. ]Wie Sie sehen, sind die Möglichkeiten, die das Paket bietet, recht vielfältig, wie auch das folgende Beispiel zeigt, in dem ein Objekt serialisiert wird:
// Klasse, deren Objekt serialisiert werden soll class myObst { function __construct() { $this->obst=array('Äpfel','Birnen'); $this->anzahl=4; } } // Optionen zum Initialisieren des Objekts $options = array ( 'addDecl' => true, 'encoding' => 'ISO-8859–1', 'addDecl'=>true, 'addDoctype' => true, 'doctype'=>'obst.dtd', 'indent' => ' ', 'typeHints' => true, 'classAsTagName' =>true, 'defaultTagName'=>'daten' ); $obst = new myObst;; $serializer = new XML_Serializer($options); $erg = $serializer->serialize($obst); if (true===PEAR::isError($erg)) { die($erg->getMessage()); } echo $serializer->getSerializedData();
Listing 23.15 Serialisierung eines Objekts
Wie Sie an den generierten Daten erkennen können, sind in diesem Fall deutlich mehr Informationen enthalten:
<?xml version="1.0" encoding="ISO-8859–1"?> <!DOCTYPE myObst SYSTEM "obst.dtd"> <myObst _class="myObst" _type="object"> <obst _type="array"> <daten _originalKey="0" _type="string">Äpfel</daten> <daten _originalKey="1" _type="string">Birnen</daten> </obst> <anzahl _type="integer">4</anzahl> </myObst>
Diese Daten könnten sowohl mit einer DTD validiert werden als auch wieder zurück in PHP-Daten konvertiert werden.
Um solche XML-Daten wieder zurück in PHP-Daten zu konvertieren, steht der Unserializer zur Verfügung, der in der Datei XML/Unserializer.php deklariert ist. Nachdem Sie ein Objekt der Klasse abgeleitet haben, können Sie hier die Methode unserialize() nutzen, um serialisierte Daten zurückzuverwandeln.
Damit der Unserializer seine Aufgabe lösen kann, benötigt er die Information, wie die Daten kodiert sind. Hierzu müssen Sie die Optionen, die Sie bei der Serialisierung genutzt haben, auch hier wieder bei der Instanziierung übergeben.
Die Optionen sind teilweise mit denen identisch, die bei der Serialisierung genutzt werden. Unterstützt werden hier die Optionen 'keyAttribute', 'typeAttribute', 'classAttribute', 'tagAsClass', 'tagMap' und 'prependAttributes'.
'keyAttribute' verhält sich in diesem Fall allerdings ein wenig anders. Und zwar können Sie hier auch ein assoziatives Array übergeben, das definiert, welcher Name (Schlüssel des Feldes) in welchen String (Wert des Feldes) konvertiert werden soll. In diesem Array können Sie einen Schlüssel namens _default definieren, der immer dann genutzt wird, wenn kein anderer Schlüssel zutrifft.
Zusätzlich stehen die folgenden Schlüssel zur Verfügung: 'complexType' kann den Wert 'array' oder 'object' übergeben bekommen. Hiermit wird definiert, in welcher Form komplexe Datenstrukturen zurückgegeben werden. Der Schlüssel 'defaultClass' definiert den Namen der Klasse, die genutzt werden soll, um Objekte zu extrahieren. Die Default-Einstellung ist 'stdClass'. Mit 'parseAttributes', das einen booleschen Wert akzeptiert, können Sie festlegen, ob die Attribute, die in den XML-Daten übergeben werden, als Array zurückgegeben werden sollen. Standardmäßig wird das nicht gemacht. Die Option 'forceEnum' fordert ein Array mit Namen von Elementen. Diese Elemente werden dann immer als indiziertes Array zurückgegeben. Den Quell-Zeichensatz können Sie mit der Option 'encoding' festlegen, und den Zeichensatz für die Ausgabe können Sie über 'targetEncoding' bestimmen. Mit der Option 'returnResult' können Sie schließlich definieren, ob die Methode unserialize() die Daten sofort zurückgibt (true) oder ob diese nur mit getUnserializedData() ausgelesen werden können (false).
Da auch hier die Einschränkungen bezüglich des verwendeten Zeichensatzes gelten, die Sie auf Seite 705 im Abschnitt über XML_Util nachlesen können, kann es durchaus passieren, dass Dateien mit Sonderzeichen nicht korrekt interpretiert werden, weil PHP sie falsch erkennt. Daher macht es Sinn, wenn Sie versuchen, auf Sonderzeichen in den XML-Daten zu verzichten. Auch Entitäten werden zurzeit noch nicht immer korrekt gehandhabt.
Ein möglicher Ausweg wäre, komplett mit UTF-8 zu arbeiten, oder Sie nutzen eine URL-Kodierung für die Sonderzeichen.
require_once('XML/Unserializer.php'); // XML-Daten ohne Umlaute $origin=' <!DOCTYPE myObst SYSTEM "obst.dtd"> <myObst _class="myObst" _type="object"> <obst _type="array"> <daten _originalKey="0" _type="string">Aepfel</daten> <daten _originalKey="1" _type="string">Birnen</daten> </obst> <anzahl _type="integer">4</anzahl> </myObst>'; // Klasse, die genutzt werden kann class myObst{}; $options = array('encoding' => 'ISO-8859–1', 'tagAsClass' => true); $unserializer = new XML_Unserializer($options); $erg = $unserializer->unserialize($origin); if (true===PEAR::isError($erg)) { die( $erg->getMessage()) ; } $target = $unserializer->getUnserializedData(); echo '<pre>'; var_dump( $target); echo '</pre>';
Listing 23.16 Deserialisierung von Daten
Die Ausgabe, die generiert wird, lautet:
object(myObst)#3 (2) { ["obst"]=> array(2) { [0]=> string(6) "Aepfel" [1]=> string(6) "Birnen" } ["anzahl"]=> int(4) }
Vielleicht sind Sie über die minimalistische Definition der Klasse myObst in der Zeile
class myObst{};
gestolpert. Damit ein Objekt dieser Klasse zurückgegeben werden kann, muss sie deklariert sein. Andernfalls würde ein Objekt der Klasse stdClass bzw. ein Objekt der Klasse zurückgegeben, deren Namen Sie mit der Option 'defaultClass' übergeben haben. Dass keine Eigenschaften deklariert sind, ist zwar nicht elegant, aber in PHP durchaus möglich.
Der Methode uneserialize() können Sie auch den Namen einer Datei übergeben, die eingelesen werden soll. Der zweite Parameter muss dann true sein. Das ist besonders interessant, da Sie auf dieser Basis z. B. auch eine RSS-Datei von einem anderen Server als Datenquelle verwenden können, um sie einfacher verarbeiten zu können.
Sowohl der Serializer als auch der Unserializer unterstützen noch die Methoden resetOptions(), setOptions() und setOption(). Die erste löscht alle definierten Optionen, und die zweite bekommt ein Array mit Optionen übergeben, das so aufgebaut sein muss wie das, das beim Konstruktor Verwendung findet. Mit der dritten Methode können Sie eine einzelne Option direkt setzen, indem Sie den Namen der Option sowie den Wert als getrennte Parameter übergeben. Das ist immer dann sehr hilfreich, wenn ein XML_Serialize- oder XML_Unserialize-Objekt mehrfach genutzt werden soll.