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.6 XML_Parser  toptop


Besprochene Version: 1.2.4 Lizenz: PHP-Lizenz 3
Klassendatei(en): XML/Parser.php; XML/Parser/Simple.php

Das Paket XML_Parser lehnt sich in Funktionsumfang und -weise stark an das an, was PHP selbst bietet. Das Paket unterstützt den eigentlichen »großen« Parser und noch eine vereinfachte Variante, den Simple-Parser für kleinere Dateien.

Der eigentliche Parser basiert auf der Idee, dass eine Funktion aufgerufen wird, wann immer ein neues Element in den XML-Daten gefunden wird. Der Parser kennt dabei den event- und den func-Modus. Im ersten sind allgemeine Handler zur Verarbeitung aller Elemente vorgesehen. Im zweiten können Sie für jedes Tag eine spezielle Funktion definieren.

Der Parser kann die XML-Daten sowohl aus einer Datei als auch aus einem String übernehmen.

Die folgenden Beispiele arbeiten mit diesen XML-Daten:

<person > 
   <name geschl="m">Homer J. Simpson</name> 
   <ort typ="privat">Springfield</ort> 
</person>

Listing 23.9 XML-Daten

In Listing 23.10 finden Sie ein Beispiel, das die Daten auf Basis einer ereignisgesteuerten Vorgehensweise verarbeitet:

require_once ('XML/Parser.php'); 
 
class myHandler 
{ 
   // Wird bei einem oeffnenden Tag aufgerufen 
   public function startHandler($xp, $name, $attribs) 
   { 
      echo "Start Tag: $name<br />"; 
      foreach ($attribs as $attrib=>$value) 
      { 
         echo "Attribut: $attrib Wert: $value<br />"; 
      } 
   } 
 
   // Wird fuer die Daten aufgerufen 
   public function cdataHandler($xp, $cdata) 
   { 
      $cdata=trim($cdata); 
      if ('' !== $cdata) 
      { 
         echo "Daten: $cdata<br />"; 
      } 
   } 
 
   // Wird bei einem oeffnenden Tag aufgerufen 
   public function endHandler($xp, $name) 
   { 
      echo "End Tag: $name<br />"; 
   } 
} 
 
// Daten werden in einem String uebergeben 
$data=' 
<person> 
   <name geschl="m">Homer J. Simpson</name> 
   <ort typ="privat">Springfield</ort> 
</person>'; 
 
 
// Neuen Parser ableiten 
$parser = new XML_Parser(); 
// Neuen Handler ableiten 
$handler = new myHandler(); 
 
// Daten uebergeben 
$parser->setInputString($data); 
// Handler an Parser uebergeben 
$parser->setHandlerObj($handler); 
// Parser aufrufen 
$erg = $parser->parse(); 
if (true=== PEAR::isError($erg)) 
{ 
   die ($erg->getMessage()); 
}

Listing 23.10 Verarbeitung von Daten mit einem ereignisgesteuerten Handler

Wie Sie sehen, ist eine Klasse namens myHandler deklariert, in der drei Methoden enthalten sind. Jede dieser Methoden bezieht sich auf einen bestimmten Teil eines XML-Elements. Die Methode startHandler() wird dann aufgerufen, wenn der Parser ein öffnendes Tag findet. endHandler() verarbeitet ein schließendes Tag, und cdataHandler() verarbeitet den eigentlichen Inhalt des Elements. Die Namen und Parameterlisten dieser Methoden sind fest vorgeschrieben, damit der Parser sie aufrufen kann.

Der Parameter $xp bezeichnet in allen Fällen eine Referenz auf den Parser, die den Methoden übergeben wird. Üblicherweise müssen Sie sich darum nicht weiter kümmern. $name bezieht sich bei den Methoden, die die Tags verarbeiten, auf den Namen des jeweiligen Tags, der darin übergeben wird.

In der Methode startHandler() ist darüber hinaus ein Parameter vorzusehen, mit dessen Hilfe die Attribute übergeben werden können, die in einem öffnenden Tag vorhanden sein können. Diese werden in Form eines assoziativen Arrays an die Methode überreicht.

Die Methode cdataHandler() sollte neben der Referenz auf den Parser noch einen weiteren Parameter unterstützen, in dem die Daten übergeben werden, die zwischen den Tags eingeschlossen sind.

Da der Code der Methoden startHandler() und endHandler() keine Besonderheiten aufweist, werde ich nur auf cdataHandler() eingehen. Ihnen sind hierbei vielleicht diese beiden Zeilen aufgefallen:

$cdata=trim($cdata); 
if ('' !== $cdata)

Würde ich nicht auf trim() zurückgreifen und alle Daten direkt verwenden, würden auch Zeilenumbrüche, Leerzeichen und Ähnliches ausgegeben. Das kann störend sein, weil dann z. B. auch der Zeilenumbruch hinter <person> als Datensatz betrachtet wird. Allerdings hat die obige Vorgehensweise auch den Nachteil, dass Informationen (Leerzeichen) eventuell verloren gehen könnten. Daher stellt diese Variante nur eine »Quick-and-Dirty-Lösung« dar. Am einfachsten ist es, wenn sich alle Tags in der XML-Quelle in einer Zeile befinden:

<person><name geschl="m">…</name><ort typ="privat">…</ort>

Um die XML-Daten zu verarbeiten, benötigen Sie ein Objekt der Klasse XML_Parser. Der Konstruktor dieser Klasse benötigt keine Parameter, aber Sie können ihm bis zu drei Stück übergeben. Der erste Parameter definiert den Zeichensatz, in dem die Quell-Daten vorliegen. Der zweite Parameter kann entweder 'event' oder 'func' sein, abhängig davon, ob Sie ereignisgesteuert arbeiten wollen oder funktionsorientiert. Mit dem dritten Wert können Sie den Zeichensatz für die Ausgabedatei festschreiben.

Die Sache mit den Zeichensätzen ist leider nicht ganz so einfach, da das Verhalten des Parsers von der verwendeten PHP-Version abhängt. Grundsätzlich werden die Strings 'UTF-8', 'ISO-8859–1' und 'US-ASCII' für die Definition des Zeichensatzes unterstützt. Nutzen Sie PHP 4, wird der für die Quelle angegebene Zeichensatz für die Ein- und Ausgabe übernommen. PHP 5 erkennt allerdings selbstständig, welcher Zeichensatz die Datenquelle nutzt. Geben Sie bei PHP 5 einen Zeichensatz für die Quelle an, wirkt dieser sich nicht auf die Quelle, sondern nur auf die Ausgabe aus.

Daher sollten Sie immer einen Zeichensatz für die Ausgabe mit angeben. Dieser überschreibt Werte, die eventuell von der Eingabe übernommen wurden. Wenn Sie keinen Zeichensatz für die Ein- und Ausgabe angeben, werden die Zieldaten bis PHP 5.0.1 mit einer ISO-8859–1-Kodierung zurückgegeben. Ab PHP 5.0.2 ist UTF-8 die Standardeinstellung.

Diesem Objekt werden zuerst die Daten übergeben, die verarbeitet werden sollen, was in diesem Beispiel mit der Methode setInputString() passiert.

Des Weiteren benötigt der Parser ein Handler-Objekt, das aus der Klasse abgeleitet wird. Dieses wird mit der Methode setHandlerObj() an den Parser übergeben. [Sollten Sie PHP 4 nutzen, denken Sie bitte daran, hier eine Referenz auf das Objekt mit & zu nutzen. ]

Nachdem alles korrekt initialisiert worden ist, kann der XML-Code durch Aufruf der Methode parse() analysiert werden. Das Script generiert diese Ausgabe:

Start Tag: PERSON 
Start Tag: NAME 
Attribut: GESCHL Wert: m 
Daten: Homer J. Simpson 
End Tag: NAME 
Start Tag: ORT 
Attribut: TYP Wert: privat 
Daten: Springfield 
End Tag: ORT 
End Tag: PERSON

Wie Sie sehen können, sind alle Daten korrekt übernommen worden. Auffallend ist allerdings, dass die Namen der Tags alle in Großbuchstaben ausgegeben wurden. Die Default-Einstellung ist, dass die Tag-Namen alle in diese Darstellung konvertiert werden. Möchten Sie das verhindern, müssen Sie der Eigenschaft folding des Parser-Objekts den Wert false zuweisen: $parser->folding=false;. Zurzeit ist noch keine Methode vorhanden, um diesen Wert zu manipulieren.

Das Beispiel aus Listing 23.10 ist nur ein Anwendungsbeispiel. Eine komplette Anwendung zur Verarbeitung von XML-Daten ist um einiges aufwändiger.

Dieser ereignisgesteuerte Ansatz ist für viele Anwendungsfälle ausreichend. Allerdings können die Methoden startHandler() und endHandler()im Einzelfall sehr umfangreich werden, wenn Sie einzelne Tags unterschiedlich verarbeiten wollen. Sollen Inhalte unterschiedlich verarbeitet werden, bietet sich der funktionsgesteuerte Modus an.

Für jedes Element, das verarbeitet werden soll, müssen zwei Funktionen vorgesehen werden. Heißt das Element name, müsste die Funktion zum Verarbeiten des öffnenden Tags xmltag_name() heißen und die für das schließende Tag xmltag_name_(). Eine Unterstützung von Namensräumen existiert in diesem Modus zurzeit nicht. Die Methode zum Verarbeiten der Inhalte heißt nach wie vor cdataHandler() und ist somit nicht auf ein bestimmtes Element bezogen. Elemente, für die keine Funktion vorhanden ist, werden ignoriert – weitgehend zumindest; der Inhalt wird trotzdem abgearbeitet, nur die Tags werden ignoriert. Allerdings ist es auch möglich, Default-Methoden vorzusehen, die immer aufgerufen werden, wenn keine Methode explizit deklariert ist.

Sie haben allerdings auch die Möglichkeit, Default-Methoden zu definieren. Die Methoden mit den Namen xmltag() und xmltag_() [Die Nutzung von xmltag_() generiert in der Version 1.2.4 noch eine Notice. ] werden immer dann aufgerufen, wenn ein Tag gefunden wird, für das nicht explizit eine Methode definiert wurde.

Die Parameterlisten entsprechen denen im Modus 'event'.

Ausgehend von einer XML-Datei, die den Inhalt von Listing 23.9 hat, soll die folgende Ausgabe erzeugt werden:

Name: Homer J. Simpson 
Geschlecht: m 
Ort: (privat) Springfield

Den entsprechenden Code finden Sie in Listing 23.11.

require_once ('XML/Parser.php'); 
 
class myHandler extends XML_Parser 
{ 
   // Eigenschaft zum Speichern eines Attributs 
   private $attr_tmp; 
   // Hilfsvariable zum Definieren, ob ein Inhalt 
   // ausgegeben werden soll 
   private $output = false; 
 
   // Konstruktor, der den Konstruktor des Parents aufruft 
   public function __construct($srcenc = null, 
                                $mode= 'event', $tgtenc= null) 
   { 
      parent::__construct($srcenc, $mode, $tgtenc); 
      $this->folding = false; 
   } 
 
   // Die beiden Universalmethoden machen nichts 
   protected function xmltag () 
   { 
      return true; 
   } 
   protected function xmltag_ () 
   { 
      return true; 
   } 
 
   // Die Methode fuer <name> 
   protected function xmltag_name($xp, $name, $attribs) 
   { 
      echo "Name: "; 
      $this->output=true; // Content soll ausgegeben werden 
      $this->attr_tmp=$attribs['geschl']; //Attribut speichern 
   } 
   // Die Methode fuer </name> 
   protected function xmltag_name_($xp, $name) 
   {  //Parameter ausgeben, vorher mit xmltag_name gespeichert 
      echo "Geschlecht: $this->attr_tmp<br />"; 
   } 
 
   // Methode fuer <ort> 
   protected function xmltag_ort($xp, $name, $attribs) 
   { 
      echo "Ort: ($attribs[typ])  "; 
      $this->output=true; 
   } 
 
   // Methode fuer </ort>_$ret_   protected function xmltag_ort_($xp, $name) 
   { 
      return true; 
   } 
 
      // Methode fuer die eigentlichen Daten 
   protected function cdataHandler($xp, $cdata) 
   {  // Sollen die Daten ausgegeben werden? 
      if (true===$this->output) 
      { 
         echo "$cdata<br />"; 
         $this->output=false; 
      } 
   } 
} 
 
$parser = new myHandler('ISO-8859–1','func'); 
 
$erg=$parser->setInputFile('data.xml'); 
if (true=== PEAR::isError($erg)) 
{ 
   die ($erg->getMessage()); 
} 
$erg = $parser->parse(); 
if (true=== PEAR::isError($erg)) 
{ 
   die ($erg->getMessage()); 
}

Listing 23.11 Konvertieren von Daten im Modus 'func'

In diesem Beispiel werden die Funktionen dazu genutzt, um zu steuern, ob die enthaltenen Daten ausgegeben werden sollen, indem der Eigenschaft output der Wert true zugewiesen wird. Das verhindert, dass Zeilenumbrüche und andere Whitespaces ungewollt ausgegeben werden.

Des Weiteren werden die XML-Daten in diesem Fall mit der Methode setInputFile() aus der Datei daten.xml übernommen.

Benötigen Sie eine kleine, überschaubare Lösung, steht noch der Simple-Parser zur Verfügung, der in der Datei XML/Parser/Simple.php definiert ist. Ein sehr einfacher Parser könnte zum Beispiel so aussehen:

require_once ('XML/Parser/Simple.php'); 
 
class mySimpleHandler 
{ 
   // Methode fuer alle Elemente 
   function handleElement($name, $attribs, $data) 
   { 
      echo "Element: $name<br />"; 
      echo "Daten: $data <br />"; 
      if (0<count($attribs)) 
      { 
         echo 'Attribute:<br />'; 
         foreach ($attribs as $attr => $value) 
         { 
           echo "$attr: $value<br />"; 
         } 
      } 
   } 
} 
 
$parser = new XML_Parser_Simple(); 
$handler = new mySimpleHandler(); 
$parser->setHandlerObj($handler); 
$erg = $parser->setInputFile('data.xml'); 
if (true=== PEAR::isError($erg)) 
{_$ret_   die ($erg->getMessage()); 
} 
$erg = $parser->parse(); 
if (true=== PEAR::isError($erg)) 
{ 
   die ($erg->getMessage()); 
}

Listing 23.12 Nutzung der Klasse XML_Parser_Simple

Die Klasse mySimpleHandler besteht nur aus einer einzelnen Methode namens handleElement(). Diese muss drei Parameter akzeptieren. Im ersten wird der Name des Elements übergeben. An zweiter Stelle werden in einem Array die Attribute des Elements übergeben. An letzter Stelle folgt dann schließlich der Inhalt des Elements.

Die anderen Methoden und Eigenschaften, wie Sie sie bei XML_Parser kennen gelernt haben, sind hier auch verfügbar, da XML_Parser_Simple von XML_Parser abgeleitet ist.

XML_Simple_Parser unterstützt aber auch die Nutzung des funktionsorientierten Modus. Hier wird auch für jedes Tag eine eigene Methode deklariert. Der Name des Elements wird dabei Bestandteil des Namens der Methode. Der Name der Funktion muss mit handleElement_ beginnen. Das heißt, die Methode für das Element name könnte innerhalb der Klasse so deklariert werden:

   function handleElement_name($name, $attribs, $data) 
   { 
      // Code zur Verarbeitung des oeffnenden Tags 
   }
 <<   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