XML::LibXML

(Auszug aus "Perl & XML" von Erik T. Ray & Jason McIntosh)

XML::LibXML ist eine weitere Schnittstelle zu einer eigentlich in C geschriebenen Bibliothek, ganz ähnlich wie XML::Parser. In diesem Fall handelt es sich um die aus dem GNOME-Projekt stammende libxml2. Im Unterschied zu XML::Parser unterstützt dieser neuere Parser auch den wichtigsten Standard zur baumorientierten Verarbeitung von XML-Dokumenten, das Document Object Model (DOM).

DOM ist ein weiterer vielzitierter XML-Standard. Er spielt bei der baumorientierten Vorgehensweise dieselbe Rolle wie SAX bei den Eventströmen. Wenn Sie sich auf das Erklettern von Bäumen in Ihrem Programm freuen und eine gewisse Wahrscheinlichkeit für den Einsatz einzelner Bestandteile in einer anderen Anwendung sehen oder verschiedene mögliche Datenquellen erwägen, dann gilt auch hier: Halten Sie sich besser an die Standardschnittstelle. Auch das Thema DOM und die Denkweise bezüglich Standardschnittstellen werden wir in DOM noch ausführlich behandeln.

Wir wollen nun diesen anderen Parser in Aktion sehen. Es wäre ein Fehler, nur ein Beispiel eines Parsers zu zeigen, wo es doch so viele gibt. Wiederum nehmen wir uns nur ein recht einfaches Beispiel vor, das im wesentlichen einfach den Parser aufruft und die Zähmung seiner Macht demonstriert. Schreiben wir ein anderes Analyseprogramm, ähnlich dem aus Beispiel Ein eventorientierter XML-Prozessor, das diesmal eine Häufigkeitsverteilung der Elemente im Dokument ausgibt.

Wir sehen dieses Programm im folgenden Beispiel. Da wir keinerlei Optionen setzen, läuft der Parser mit seinen Standardeinstellungen. Im wesentlichen liest der Parser das Dokument aus einem Dateihandle und liefert als Ergebnis ein DOM-Objekt, d. h. eine Struktur aus wohldefinierten Objekten. Unser Programm sucht das Dokumentelement, durchläuft den gesamten Baum und baut dabei den Hash der Elementnamen und ihrer Häufigkeitszähler auf.

Beispiel: Ein Programm zur Berechnung einer Häufigkeitsverteilung

use XML::LibXML;
use IO::Handle;
      
# Initialisierung des Parsers      
my $parser = new XML::LibXML;

# Ein Dateihandle wird eröffnet und der Parser gestartet
my $fh = new IO::Handle;
if( $fh->fdopen( fileno( STDIN ), "r" )) {
      my $doc = $parser->parse_fh( $fh );
      my %dist;
      &proc_node( $doc->getDocumentElement, \%dist );
      foreach my $item ( sort keys %dist ) {
      print "$item: ", $dist{ $item }, "\n";
      }
      $fh->close;
}

# Verarbeitung eines XML-Knotens: Update des zugehörigen Zählers
# und Verarbeitung der Kindelemente
#
sub proc_node {
      my( $node, $dist ) = @_;
      return unless( $node->nodeType eq &XML_ELEMENT_NODE );
      $dist->{ $node->nodeName } ++;
      foreach my $child ( $node->getChildnodes ) {
      &proc_node( $child, $dist );
      }
}

Beachten Sie, daß wir in diesem Fall nicht einen Dateinamen verwenden, sondern ein Dateihandle-Objekt aus der IO::Handle-Klasse. Wie Sie vielleicht wissen, sind die Dateihandle von Perl oft Kreaturen mit einer gewissen Magie und subtilen Fähigkeiten. Sie erlauben es, aus sehr verschiedenen Quellen Zeichendaten auf einheitliche Weise in Ihr Programm zu pumpen. Beispiele sind Dateien von der Festplatte, geöffnete Netzwerksockets, Tastaturdaten, Datenbanken oder beliebige andere Datenspeicher. Hat man ein Dateihandle geöffnet, dann bietet es stets dieselbe Schnittstelle, unabhängig von der Datenquelle. Das ergänzt sich sehr gut mit unserer XML-orientierten Ideologie, so flexiblen und wiederverwendbaren Code wie möglich zu schreiben. Letzten Endes ist es einem XML-Dokument egal, woher es gelesen wurde, warum sollten wir uns also auf eine einzige Art des Lesens von Daten beschränken?

Nach dem Parsing-Vorgang erhalten wir als Ergebnis ein Dokumentobjekt. Dieses Objekt bietet eine Methode, mit der wir eine Referenz auf das Dokumentelement erhalten – das an der Wurzel des Objektbaums stehende Element. Wir füttern dieses Element in eine rekursive Subroutine namens proc_node( ) , die ein Element nach dem anderen verarbeitet und eine Hashvariable pflegt. Rekursion ist bei der Verarbeitung von XML stets eine naheliegende Technik, da die Dokumente eine fraktale Natur haben: Die für ein Element geltenden Regeln sind im wesentlichen unabhängig von der Tiefe oder Position im Dokument. Das gilt selbst für das Wurzelelement, das das Dokument in seiner Gesamtheit repräsentiert (vom Prolog abgesehen). Beachten Sie die Prüfung des »node type«, also des Knotentyps. Sie dient der Unterscheidung zwischen Elementen und allen anderen Teilen des Dokuments, zum Beispiel Textdaten oder PIs.

Die Funktion ruft für jedes Elementobjekt dessen Methode getChildnodes( ) auf, um die Kindelemente zu verarbeiten. Dieser Aufruf stellt den wesentlichen Unterschied zwischen der eventorientierten und der baumorientierten Vorgehensweise dar. Statt dem Eventstrom das Steuerruder zu übergeben, der dann durch Aufruf von Subroutinen die Daten in einer irgendwie unvorhersagbaren Reihenfolge in unser Programm hineinschaufelt, nehmen wir die Verantwortung für die Navigation durch das Dokument selbst in die Hand. Normalerweise beginnen wir mit dem Dokumentelement und steigen von dort den Baum hinauf, wobei wir die Kinder eines Elements – beginnend mit dem ersten – durchlaufen, so wie es auch der Parser täte. In diesem Fall haben wir aber die Freiheit, das Dokument in einer ganz anderen Art und Weise zu durchlaufen, und müssen nicht unbedingt dem Parser folgen. Wir können uns rückwärts bewegen, hin- und herspringen, Schleifen einbauen – der Himmel ist die Grenze. Hier sehen wir die Ausgabe des Beispielprogramms, das ein Kapitel aus einem Buch in DocBook XML analysiert:

$ xfreq < ch03.xml
chapter: 1
citetitle: 2
firstterm: 16
footnote: 6
foreignphrase: 2
function: 10
itemizedlist: 2
listitem: 21
literal: 29
note: 1
orderedlist: 1
para: 77
programlisting: 9
replaceable: 1
screen: 1
section: 6
sgmltag: 8
simplesect: 1
systemitem: 2
term: 6
title: 7
variablelist: 1
varlistentry: 6
xref: 2

Die Ausgabe des Ergebnisses beansprucht nur wenige Zeilen Quelltext, aber für die Gewinnung der Daten ist eine Menge Arbeit erforderlich. Das geschieht aber dank der in C geschriebenen Bibliothek sehr schnell.

  

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Perl & XML bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2003 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Perl & XML" 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.

O’Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de