Document Object Model (DOM)

Mit dem Document Object Model (DOM) bietet das World Wide Web Consortium (W3C) einen mächtigen Standard an, der eine plattform- und sprachunabhängige neutrale Programmierschnittstelle für den lesenden und schreibenden Zugriff auf gültige HTML und wohlgeformte XML-Dokumente definiert.

PHP 5 bietet mit seiner DOM-Erweiterung, die nicht abwärtskompatibel zur DOM-XML-Erweiterung von PHP 4 ist, eine vollständige Implementierung der "Level 2 Core"-Version des DOM-Standards. Teilweise werden auch Bestandteile ("Load and Save") der neueren Version "Level 3" umgesetzt.

Das Document Object Model fasst jeden Bestandteil eines XML-Dokumentes als einen Knoten auf. Das Dokument selbst (DOMDocument), seine Elemente (DOMElement) sowie deren Attribute (DOMAttr) und textuelle Inhalte (DOMText) werden durch Objekte entsprechender Knotenklassen repräsentiert, die untereinander mit Referenzen verknüpft sind. Abbildung 8.3 zeigt den DOM-Objektbaum für das XML-Dokument aus Beispiel 8.1.

Abbildung 8.3. DOM-Repräsentation des Buchkatalogs

DOM-Repräsentation des Buchkatalogs


Die DOM-Implementierung von PHP 5 umfasst 29 Klassen mit insgesamt 360 Methoden. Wir konzentrieren uns an dieser Stelle auf die wichtigsten (Tabelle 8.1).

Tabelle 8.1. Die wichtigsten Klassen des Document Object Model

KlasseElternklasse oder SchnittstelleAufgabe
DOMNode Basisklasse der verschiedenen Knotenklassen eines DOM-Baumes.
DOMDocumentDOMNodeBildet den Einstiegspunkt des DOM-Baumes.
DOMElementDOMNodeRepräsentiert ein XML-Element und bietet Methoden für den Zugriff auf XML-Elemente.
DOMAttrDOMNodeRepräsentiert ein Attribut eines XML-Elementes.
DOMCharacterDataDOMNodeRepräsentiert den Character-Data-Teil eines XML-Elementes.
DOMTextDOMCharacterDataRepräsentiert textuelle Inhalte eines XML-Dokuments.
DOMNodeListTraversableRepräsentiert eine Menge von Knoten.
DOMXPath Ermöglicht das Formulieren von XPath-Anfragen.
DOMExceptionExceptionAusnahmeklasse.


Laden und Speichern von XML-Dokumenten

Die Methode DOMDocument::load($filename), die sowohl auf einem Objekt als auch statisch aufgerufen werden kann, lädt ein XML-Dokument aus einer Datei. Wird die Methode statisch aufgerufen, so liefert sie ein Objekt der Klasse DOMDocument als Ergebnis (siehe beispielsweise Beispiel 8.12). DOMDocument::loadXML($xml) lädt ein XML-Dokument aus einem String, die Funktion dom_import_simplexml($sxe) erzeugt ein Objekt der Klasse DOMDocument aus einem Objekt der Klasse SimpleXMLElement.

Analog laden die Methoden DOMDocument::loadHTMLFile($filename) und DOMDocument::loadHTML($html) ein HTML-Dokument aus einer Datei oder aus einem String.

Die Methoden DOMDocument::save($filename) und DOMDocument::saveXML() speichern ein DOMDocument-Objekt als XML-Daten in eine Datei oder einen String. Für HTML-Dokumente gibt es entsprechend die Methoden DOMDocument::saveHTMLFile($filename) und DOMDocument::saveHTML().

Die genannten Methoden nutzen das Streams-System von PHP 5 und können daher, je nachdem welche Stream-Unterstützungen in PHP einkompiliert wurden, beispielsweise eine XML-Datei von einem entfernten HTTP-Server öffnen oder auf einem FTP-Server speichern. An Stelle eines Dateinamens ist hierbei die entsprechende URL als $filename anzugeben.

Erzeugen eines neuen XML-Dokumentes

In Beispiel 8.9 erzeugen wir zunächst ein Objekt der Klasse DOMDocument. Dem Konstruktor übergeben wir die gewünschte Version des XML-Standards ('1.0') und die zu verwendende Zeichenkodierung ('iso-8859-1').

Die Methode DOMDocument::createElement() erzeugt ein neues Objekt der Klasse DOMElement. Über die Methode DOMNode::appendChild() wird dieses dann an der gewünschten Stelle in den DOM-Baum "eingehängt".

Beispiel 8.9: Erzeugen eines neuen XML-Dokumentes

<?php
$document = new DOMDocument('1.0', 'iso-8859-1');
$document->formatOutput = TRUE;
 
$books = $document->appendChild(
  $document->createElement('books')
);
 
$psmp5 = $books->appendChild(
  $document->createElement('book')
);
 
$psmp5->setAttribute('lang', 'de');
 
$psmp5->appendChild(
  $document->createElement(
    'author',
    'Sebastian Bergmann'
  )
);
 
$psmp5->appendChild(
  $document->createElement(
    'title',
    'Professionelle Softwareentwicklung mit PHP 5'
  )
);
 
$psmp5->appendChild(
  $document->createElement(
    'isbn',
    '3-89864-229-1'
  )
);
 
print $document->saveXML();
?>
<?xml version="1.0" encoding="iso-8859-1"?>
<books>
  <book lang="de">
    <author>Sebastian Bergmann</author>
    <title>Professionelle Softwareentwicklung mit PHP 5</title>
    <isbn>3-89864-229-1</isbn>
  </book>
</books>


Erzeugen eines neuen XML-Dokumentes durch direkte Verwendung der DOM-Klassen, wie es in Beispiel 8.9 gezeigt ist, kann recht aufwändig werden. In solchen Fällen bietet es sich an, die DOM-Klassen durch Vererbung zu erweitern und für den konkreten Verwendungszweck anzupassen.

Die Klasse Book (Beispiel 8.10) erweitert die Klasse DOMElement um die für das <book>-Element spezifischen Methoden setAuthor($author), setISBN($isbn), setLanguage($language) und setTitle($title). So wird dem Verwender der Klasse das Aufrufen von DOMDocument::createElement() und DOMNode::appendChild() abgenommen.

Beispiel 8.10: Die Klasse Book

<?php
class Book extends DOMElement {
  private $document;
 
  public function __construct(DOMDocument $document) {
    parent::__construct('book');
    $this->document = $document;
  }
 
  public function setAuthor($author) {
    $this->appendChild(
      $this->document->createElement(
        'author',
        $author
      )
    );
  }
 
  public function setISBN($isbn) {
    $this->appendChild(
      $this->document->createElement(
        'isbn',
        $isbn
      )
    );
  }
 
  public function setLanguage($language) {
    $this->setAttribute('lang', $language);
  }
 
  public function setTitle($title) {
    $this->appendChild(
      $this->document->createElement(
        'title',
        $title
      )
    );
  }
}
?>


Die Klasse Books (Beispiel 8.11) erweitert die Klasse DOMDocument und bietet mit ihrer Methode createBook() eine einfache Möglichkeit, ein neues <book>-Element zu erzeugen.

Beispiel 8.11: Die Klasse Books

<?php
require_once 'Book.php';
 
class Books extends DOMDocument {
  private $books;
 
  public function __construct() {
    parent::__construct('1.0', 'iso-8859-1');
 
    $this->books = $this->appendChild(
      $this->createElement('books')
    );
 
    $this->formatOutput = TRUE;
  }
 
  public function createBook() {
    $book = new Book($this);
    $this->books->appendChild($book);
 
    return $book;
  }
}
 
$books = new Books;
$book  = $books->createBook();
 
$book->setAuthor('Sebastian Bergmann');
$book->setISBN('3-89864-229-1');
$book->setTitle(
  'Professionelle Softwareentwicklung mit PHP 5'
);
$book->setLanguage('de');
 
print $books->saveXML();
?>


Beispiel 8.11 erzeugt dieselbe Ausgabe wie Beispiel 8.9.

Verwenden der DOMNodeList-Klasse

Die Klasse DOMNodeList repräsentiert eine Menge von Knoten, also Objekten der Klasse DOMNode. Es wird keine spezielle Ordnung für die Knoten vorgegeben. DOMNodeList implementiert die Schnittstelle Traversable (siehe Kapitel 3), entsprechende Objekte können daher mit dem foreach-Operator iteriert werden.

Beispiel 8.12 benutzt die Methode DOMDocument::getElementsByTagName(), um alle <author>-Elemente zu erhalten. Als Ergebnis liefert die Methode ein Objekt der Klasse DOMNodeList, das die entsprechenden DOMElement-Objekte enthält. $author->nodeValue greift auf den Wert des DOMText-Knotens zu, der an dem von $author referenzierten DOMElement-Objekt hängt.

Beispiel 8.12: Verwenden der DOMNodeList-Klasse

<?php
$document = DOMDocument::load('books.xml');
$authors  = $document->getElementsByTagName('author');
 
foreach ($authors as $author) {
  print $author->nodeValue . "\n";
}
?>
Sebastian Bergmann
Hakan Kücükyilmaz
Thomas M. Haas
Alexander Merz


Formulieren von XPath-Anfragen

Über die Klasse DOMXPath können XPath-Anfragen an einen DOM-Baum gestellt werden. Das Ergebnis ist wieder ein Objekt der Klasse DOMNodeList.

Beispiel 8.13: Formulieren von XPath-Anfragen

<?php
$document = DOMDocument::load('books.xml');
$xpath    = new DOMXPath($document);
 
foreach ($xpath->query('book/title') as $title) {
  print $title->nodeValue . "\n";
}
?>
Professionelle Softwareentwicklung mit PHP 5
PHP 5


Validieren von XML-Dokumenten

Neben der Verarbeitung von XML-Dokumenten ermöglicht die PHP-DOM-Erweiterung auch die Validierung von XML-Dokumenten gegen Spezifikationen in den Formaten Document Type Definition (DTD), XML Schema (XSD) und RelaxNG (RNG).

XML Schema ist die offizielle Nachfolgetechnologie des W3C für die Document Type Definition. Ein Schemas wird benutzt, um eine Klasse von XML-Dokumenten zu definieren. Anhand eines Schemas kann für ein konkretes XML-Dokument überprüft werden, ob es die Schema-Definition erfüllt. Man sagt, ein XML-Dokument validiert gegen ein XML Schema.

Beispiel 8.14 zeigt die Verwendung der von PHP 5 zur Verfügung gestellten Methode DOMDocument::schemaValidate().

Beispiel 8.14: XML-Schema-Validierung

<?php
$document = DOMDocument::load('books.xml');
 
if ($document->schemaValidate('books.xsd')) {
  print 'books.xml entspricht der XML-Schema-Deklaration '.
        'in books.xsd.';
}
?>
books.xml entspricht der XML-Schema-Deklaration in books.xsd.


Beispiel 8.15: XML-Schema-Deklaration für den Buchkatalog


<?xml version="1.0"?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="books">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element maxOccurs="unbounded" ref="book"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="book">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="author" minOccurs="1" maxOccurs="unbounded"/>
        <xsd:element ref="title"  minOccurs="1"/>
        <xsd:element ref="isbn"   minOccurs="1"/>
      </xsd:sequence>

      <xsd:attribute name="lang" use="required" type="xsd:string"/>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="author" type="xsd:string"/>
  <xsd:element name="title"  type="xsd:string"/>
  <xsd:element name="isbn"   type="xsd:string"/>
</xsd:schema>



RelaxNG ist eine parallel zu XML Schema entstandene Schema-Sprache für die Definition von XML-Dokumenten, die derzeit ISO-standardisiert wird. Sie wird nicht vom W3C unterstützt, nutzt aber die von XML Schema definierten Datentypen. RelaxNG tritt an, eine leichter erlernbarere Alternative zu XML Schema zu sein.

Beispiel 8.14 zeigt die Verwendung der Methode DOMDocument::relaxngValidate().

Beispiel 8.16: RelaxNG-Validierung

<?php
$document = DOMDocument::load('books.xml');
 
if ($document->relaxngValidate('books.rng')) {
  print 'books.xml entspricht der RelaxNG-Deklaration '.
        'in books.rng.';
}
?>
books.xml entspricht der RelaxNG-Deklaration in books.rng.


Beispiel 8.17: RelaxNG-Deklaration für den Buchkatalog


<?xml version="1.0" encoding="UTF-8"?>

<grammar xmlns="http://relaxng.org/ns/structure/1.0"
         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <start>
    <element name="books">
      <oneOrMore>
        <element name="book">
          <attribute name="lang">
            <data type="NMTOKEN"/>
          </attribute>

          <oneOrMore>
            <element name="author">
              <text/>
            </element>
          </oneOrMore>

          <element name="title">
            <text/>
          </element>

          <element name="isbn">
            <text/>
          </element>
        </element>
      </oneOrMore>
    </element>
  </start>
</grammar>



Vor- und Nachteile

  • + Implementierung eines mächtigen Standards.

  • + Lese- und Schreibzugriff auf beliebige XML-Elemente möglich.

  • - Langsam und speicherintensiv, da ein vollständiger Baum von PHP-Objekten erzeugt werden muss.