Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 PEAR – Einführung
2 Authentication
3 Caching
4 Date and Time
5 File Formats
6 HTTP
7 Internationalization
8 Mail
9 Networking
10 PHP
11 Text
12 Web Services
13 Benchmarking
14 Configuration
15 Database
16 File System
17 HTML
18 Images
19 Logging
20 Math
21 Numbers
22 Tools and Utilities
23 XML
24 Selbst Pakete erstellen
25 PECL
Index
Ihre Meinung?

Spacer
 <<   zurück
PHP PEAR von Carsten Möhrke
Anwendung und Entwicklung – Erweiterungen für PHP schreiben
Buch: PHP PEAR

PHP PEAR
798 S., 39,90 Euro
Rheinwerk Computing
ISBN 3-89842-580-0
gp 23 XML
  gp 23.1 XML_Util
  gp 23.2 XML_Beautifier
  gp 23.3 XML_RSS
  gp 23.4 XML_Tree
  gp 23.5 XML_DTD
  gp 23.6 XML_Parser
  gp 23.7 XML_Wddx
  gp 23.8 XML_Serializer
  gp 23.9 XML_Indexing


Rheinwerk Computing

23.4 XML_Tree  toptop


Besprochene Version: 2.0.0RC2 Lizenz: PHP-Lizenz 2.02
Klassendatei(en): HTML/Tree.php

Die Klasse XML_Tree eröffnet Ihnen die Möglichkeit, mit einfachen Mitteln XML-Bäume aufzubauen und zu verwalten. XML-Dokumente als Bäume zu betrachten vereinfacht die Arbeit mit ihnen deutlich, so dass diese Vorgehensweise sehr beliebt ist, was auch daran zu erkennen ist, dass dieses Paket eine Grundlage für viele andere PEAR-Pakete darstellt.

Ein Baum besteht immer aus einem Wurzel-Element, unter dem meist verschiedene Kind-Elemente eingehängt werden. Zwar wären Kinder unterhalb des Wurzel-Elements nicht unbedingt notwendig, aber es ist doch eher selten, dass ein XML-Dokument genutzt wird, das nur aus dem Root-Element, sprich der Wurzel, besteht. Unterhalb eines Child-Elements können wiederum weitere Kinder folgen. Folgen keine weiteren Elemente mehr, bezeichnet man ein solches Kind auch als Blatt. Jedes Element – unabhängig davon, ob Root, Child oder Leaf – wird auch als Node, also Knoten, bezeichnet.

Nachfolgend soll ein Script dieses XML-Dokument als Baum aufbauen:

<?xml version="1.0"?> 
<person> 
   <name> 
      <vorname>Carsten</vorname> 
      <nachname>Möhrke</nachname 
   </name> 
   <wohnort> 
      <ort>Bielefeld</ort> 
   </wohnort> 
   <member /> 
</person>

Listing 23.4 Beispiel einer XML-Datei

Dieses XML-Dokument besteht also aus einem Root-Element, unter dem die beiden Kinder name und wohnort zu finden sind. Diese beiden verfügen jeweils wieder über mindestens ein Kind. Als Letztes ist noch das leere Element <member /> zu finden.

require_once 'XML/Tree.php'; 
 
// Neuen Baum generieren 
$baum = new XML_Tree; 
 
// Neues Wurzel-Element im Baum eintragen 
$wurzel =$baum->addRoot('person'); 
if (PEAR::isError($wurzel)) 
{ 
    die($wurzel->getMessage()); 
} 
 
// Knoten name unterhalb der Wurzel anlegen 
$node_name = $wurzel->addChild('name'); 
if (PEAR::isError($node_name)) 
{ 
    die($node_name->getMessage()); 
} 
 
// Vornamen unterhalb von name einhaengen 
$node_vorname = $node_name->addChild('vorname','Carsten'); 
if (PEAR::isError($node_vorname)) 
{ 
    die($node_vorname->getMessage()); 
} 
 
// Nachnamen unterhalb von name einhaengen 
$node_nachname = $node_name->addChild('nachname','Möhrke'); 
if (PEAR::isError($node_nachname)) 
{ 
    die($node_nachname->getMessage()); 
} 
 
 
// Aufbau des Elements Wohnort 
$node_wohnort = $wurzel->addChild('wohnort'); 
if (PEAR::isError($node_wohnort)) 
{ 
    die($node_wohnort->getMessage()); 
} 
 
// Ort einfuegen 
$node_ort = $node_wohnort->addChild('ort','Bielefeld'); 
if (PEAR::isError($node_ort)) 
{ 
    die($node_ort->getMessage()); 
} 
 
// Leeres Element einfuegen 
$node_member = $wurzel->addChild('member'); 
if (PEAR::isError($node_member)) 
{ 
    die($node_member->getMessage()); 
} 
// Baum ausgeben 
echo $baum->get();

Listing 23.5 Generieren eines einfachen Baums mit XML_Tree

Aufgrund der Länge des Scripts erscheint der Aufwand, einen Baum auf diesem Weg zu generieren, vielleicht ein wenig groß. Soll Ihr Script aber häufig Daten automatisiert übernehmen und in valides XML wandeln, so ist dieser Aufwand absolut akzeptabel.

Nachdem ein neues XML_Tree-Objekt instanziiert wurde, müssen Sie als Erstes ein Root-Element mithilfe von addRoot() hinzufügen. Die Methode liefert die Referenz auf ein Node-Objekt zurück. Zumindest ist das dann der Fall, wenn kein Fehler auftritt. Sollte ein Fehler auftreten, wird ein PEAR_Error zurückgegeben.

Die Methode addChild() hängt unterhalb eines Elements (unabhängig davon, ob es sich um das Root- oder ein anderes Element handelt) ein weiteres Element ein. addChild() wird immer mit dem Objekt aufgerufen, unter dem ein weiteres Kind eingefügt werden soll. addRoot() und addChild() unterstützen hierbei eine identische Parameterliste. Beide bekommen als Erstes den Namen des Elements übergeben, der sich dann später im Tag wiederfinden soll. Danach kann ein Wert folgen, der dann zwischen den Tags ausgegeben wird. Geben Sie keinen Wert an und fügen Sie auch keine Kinder ein, so ergibt sich ein leeres Element, wie es in diesem Fall für <member /> genutzt wurde. Bei den übergebenen Werten müssen Sie sich übrigens keine Gedanken um Sonderzeichen machen. Solange Sie die Daten im ISO-8859–1-Zeichensatz übergeben, werden die Sonderzeichen alle in numerische Entitäten konvertiert, so dass auch keine DTD notwendig ist.

Möchten Sie, dass ein Element über Attribute verfügt, so können Sie diese als nächsten Parameter in Form eines Arrays übergeben. Hierbei werden die Schlüssel des Arrays zum Namen, und die Werte bleiben die Werte. Soll das Root-Element aus dem obigen Beispiel noch um zwei Attribute ergänzt werden, könnte das so aussehen:

$attr=array("geschl"=>"m", 
            "jahrgang"=>"1971"
      ); 
$wurzel =$baum->addRoot('person','',$attr);

Da es sich um das Root-Element handelt, wird kein Inhalt übergeben. Die Inhalte des Arrays werden übernommen und als Attribute eingefügt, so dass das Root-Element so aussehen würde:

<person geschl="m" jahrgang="1971">

Die Methode get(), die sich in der letzten Zeile findet, liest den Baum komplett aus und gibt das XML-Dokument als String zurück. Dieser muss natürlich nicht, wie in diesem Beispiel, ausgegeben werden. Die Daten können natürlich auch in einer Datei abgelegt werden. Alternativ können Sie für die Ausgabe auf einer Webpage auch die Methode dump() nutzen.

Zwar unterstützt das Paket zurzeit keine Möglichkeit, eine Doctype-Definition einzufügen oder festzulegen, welcher Zeichensatz genutzt werden soll, aber Sie haben zumindest die Möglichkeit, mit Namensräumen zu arbeiten.

Die Namensräume sind weitgehend manuell zu verwalten. Das heißt, der Namensraum muss registriert werden und kann dann bei den entsprechenden Tags manuell mit angegeben werden. Um das Root-Element um zwei Namensräume zu ergänzen, müsste zweimal die Methode registerName() aufgerufen werden. Sie bekommt das Namensraum-Präfix sowie die dazugehörige URL übergeben.

$wurzel =$baum->addRoot('person','',$attr); 
$wurzel->registerName('firma','http://www.example.com'); 
$wurzel->registerName('privat','http://www.example.net'); 
// Resultat: 
// <person geschl="m" jahrgang="1971" 
//              xmlns:firma='http://www.example.com' 
//              xmlns:privat='http://www.example.com'>

Um ein Element nun einem dieser Namensräume zuzuordnen, muss er direkt mit angegeben werden, wenn Sie die Methode addRoot() bzw. addChild() aufrufen, also z. B. $wurzel->addChild('privat:name').

Das Paket kann allerdings auch bestehende XML-Daten einlesen und verarbeiten. Diese Daten können entweder in Form einer Datei oder in Form eines Strings vorliegen. Um einen String als Grundlage zu nehmen, nutzen Sie die Methode getTreeFromString() und übergeben ihr den String als Parameter. Möchten Sie einen Baum aus einer Datei generieren, steht getTreeFromFile() zur Verfügung. Der Name der einzulesenden Datei ist hierbei allerdings schon dem Konstruktor zu übergeben.

$baum = new XML_Tree("daten.xml"); 
$wurzel=$baum->getTreeFromFile();

Beide Methoden lesen die Daten ein und bauen den kompletten Baum im Speicher auf. Nachdem ein Baum im Speicher aufgebaut wurde, stellt sich natürlich die Frage, wie er manipuliert werden kann. Hierzu sind verschiedene Methoden implementiert, die ich Ihnen gleich vorstellen werde. Zuvor aber noch ein kleiner Hinweis auf die »Quick and Dirty«-Variante.

Da das Paket noch in PHP 4-Syntax vorliegt, sind die einzelnen Eigenschaften in ihrer Sichtbarkeit noch nicht eingeschränkt. Die direkten Kinder eines jeden Knotens werden in einem Array namens children[] verwaltet, auf das Sie direkt zugreifen können. Wäre also z. B. die Datei aus Listing 23.4 eingelesen worden, so liefert die Methode eine direkte Referenz auf das Wurzel-Element. Wäre dieses in $wurzel abgelegt, so ergibt $wurzel->children[0] eine Referenz auf den Knoten name und $wurzel->children[1] eine Referenz auf das Element wohnort. Es bleibt abzuwarten, ob dieser direkte Zugriff auf die Eigenschaft children in zukünftigen Versionen noch möglich sein wird.

Da in den meisten Fällen der Aufbau der XML-Datei aber bekannt sein dürfte, können Sie die Elemente auch über ihre Namen bzw. den Pfad ansprechen. Den Inhalt eines Elements inklusive der Tags können Sie jeweils mit der Methode get() auslesen. Das get(), das Sie schon kennen, bezog sich auf einen ganzen Baum, aber auch auf der Ebene der einzelnen Knoten ist diese Methode definiert. Zu beachten ist, dass sie nicht nur den Inhalt des aktuell selektierten Knotens zurückliefert, sondern auch alle Inhalte von untergeordneten Knoten, wenn es denn noch welche gibt.

Um den Wert eines Attributs auszulesen, ist wiederum getAttribute() vorgesehen. Diese Methode bezieht sich nur auf das aktuelle Objekt, aus dem heraus sie aufgerufen wird, und gibt den Wert des Attributs zurück. Ist das Attribut nicht deklariert, ist der Rückgabewert null.

Da Sie nach dem Einlesen der Datei nur eine Referenz auf das Root-Element haben, stellt sich natürlich die Frage, wie Sie auf die untergeordneten Knoten zugreifen können. Die folgenden Beispiele beziehen sich auf diesen XML-Code:

<daten> 
   <ort> 
      <vorwahl>0521</vorwahl> 
      <name>Bielefeld</name> 
   </ort> 
</daten>

Listing 23.6 XML-Beispieldatei

Die erste Variante ist, den Knoten über einen Pfad anzusprechen. Hierfür ist getNodeAt() vorgesehen. Die Methode bekommt den Pfad als String oder als Array übergeben und liefert eine Referenz auf den gewünschten Knoten zurück– oder ein PEAR_Error-Objekt, wenn der Knoten nicht gefunden wird.

$baum = new XML_Tree("daten.xml"); 
// $wurzel referenziert <daten> 
$wurzel=$baum->getTreeFromFile(); 
if (PEAR::isError($wurzel)) 
{ 
   die($wurzel->getMessage()); 
} 
// $element ist <name> 
$element=$wurzel->getNodeAt("ort/name"); 
if (PEAR::isError($element)) 
{ 
   die($element->getMessage()); 
} 
//gibt <name>Bielefeld</name> aus 
echo $element->get();

Die andere Variante ist getElement(). Hierbei wird das gewünschte Element mithilfe eines Arrays adressiert, das aus Zahlen besteht. Die Zahl definiert jeweils, um das wievielte Kind es sich handelt, und die Reihenfolge definiert, in welcher Hierarchiestufe das gewünschte Element zu suchen ist. Ausgehend von obigem XML-Code würde das Array, um auf name zu verweisen, die Werte 0 und 1 enthalten.

$path=array(0,1); 
$element=$wurzel->getElement($path); 
// $element verweist jetzt auf <name>

Die 0 bezeichnet hierbei also <ort> und die 1 <name>. Wichtig ist, dass die Datei mit UNIX-Zeilenumbrüchen (\n) oder ganz ohne Zeilenumbrüche vorliegen muss. Liegt die Datei mit DOS-Zeilenumbrüchen (\r\n) vor, werden beim Einlesen Elemente erzeugt, die nur einen Zeilenumbruch enthalten und durch die Methode zurückgegeben werden. Diese Methode bietet gegenüber getNodeAt() den Vorteil, dass es kein Problem darstellt, wenn mehrere gleichnamige Elemente direkt aufeinander folgen.

Haben Sie ein Element gefunden, das manipuliert werden soll, stehen wiederum verschiedenste Möglichkeiten zur Verfügung. Zum Ersten stellt sich die Frage, wie Sie die untergeordneten Knoten verändern können. Um einen Knoten komplett zu entfernen, ist die Methode removeChild() vorgesehen. Sie bekommt die Nummer des direkten Kindes übergeben, das entfernt werden soll. 0 bezeichnet das erste Kind, 1 das zweite etc. Negative Zahlen bedeuten, dass von hinten gezählt wird. -1 ist das letzte Kind, -2 das vorletzte usw.

Mit der schon bekannten Methode addChild() können Sie, wie schon erläutert wurde, auch hier wieder neue Elemente einfügen. Sie können allerdings auch einen bestehenden Knoten bzw. einen ganzen Teilbaum einfügen, indem Sie insertChild() nutzen. Diese Methode bekommt den Pfad und die Position übergeben, an welcher Stelle der Knoten eingefügt werden soll. Des Weiteren müssen Sie danach natürlich die Referenz auf den bestehenden Knoten übergeben, der eingefügt werden soll.

Natürlich stehen auch Methoden zur Verfügung, um das aktuelle Element zu bearbeiten. Mit setAttribute()können Sie Attribute neu einfügen bzw. den Wert eines bestehenden Attributs überschreiben. Um ein bestehendes Attribut zu entfernen, ist die Methode unsetAttribute() vorgesehen, die den Namen des zu eliminierenden Attributs übergeben bekommt.

Der eigentliche Inhalt eines Elements kann mit der Methode setContent() verändert werden, die den Inhalt direkt übergeben bekommt.

Um die XML-Beispieldatei aus Listing 23.6 in diese Datei zu transformieren:

<daten> 
   <ort vorwahl="0521"> 
      <name>Hamburg</name> 
      <bundesland>NRW</bundesland> 
   </ort> 
</daten>

könnten Sie das Script aus Listing 23.7 nutzen:

require_once 'XML/Tree.php'; 
 
// Neuen Baum generieren 
$baum = new XML_Tree("daten.xml"); 
 
// Daten einlesen 
$wurzel=$baum->getTreeFromFile(); 
if (PEAR::isError($wurzel)) 
{ 
   die($wurzel->getMessage()); 
} 
 
// Knoten ort selektieren 
$node_ort=$wurzel->getNodeAt('ort'); 
if (PEAR::isError($node_ort)) 
{ 
   die($node_ort->getMessage()); 
} 
 
$node_vorwahl=$node_ort->getNodeAt('vorwahl'); 
if (PEAR::isError($node_vorwahl)) 
{ 
   die($node_vorwahl->getMessage()); 
} 
// Content extrahieren 
$vorwahl=strip_tags($node_vorwahl->get()); 
// Knoten wird nicht mehr benoetigt 
unset ($node_vorwahl); 
 
// Vorwahl als Attribut speichern 
$node_ort->setAttribute('vorwahl',$vorwahl); 
 
// Element <vorwahl> entfernen 
$node_ort->removeChild(0); 
 
// Element <bundesland> einfuegen 
$node_lage=$node_ort->addChild('bundesland','NRW'); 
if (PEAR::isError($node_lage)) 
{ 
   die($node_lage->getMessage()); 
} 
// Baum ausgeben 
$baum->dump();

Listing 23.7 Script zum Manipulieren einer XML-Datei

Ich denke, dass XML_Tree ein Paket ist, das viele Dinge deutlich vereinfachen kann. Ein wenig verwirrend bei der Nutzung ist, dass einige Methoden mit gleichem Namen für den Baum und für einzelne Elemente definiert sind. Sobald man sich daran gewöhnt hat, ist das aber kein Problem.

 <<   zurück
     
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: PHP PEAR
PHP PEAR
Jetzt Buch bestellen!
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: PHP 5.6 und MySQL 5.7






 PHP 5.6 und
 MySQL 5.7


Zum Rheinwerk-Shop: Einstieg in PHP 5.6 und MySQL 5.6






 Einstieg in PHP 5.6
 und MySQL 5.6


Zum Rheinwerk-Shop: Responsive Webdesign






 Responsive Webdesign


Zum Rheinwerk-Shop: Moderne Websites entwickeln






 Moderne Websites
 entwickeln


Zum Rheinwerk-Shop: MySQL 5.6






 MySQL 5.6


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo








Copyright © Rheinwerk Verlag GmbH 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern