Open Source im professionellen Einsatz
Linux-Magazin 08/2005

XML-Parser für Perl im Vergleich

Datenfischer

XML ist ein nicht überall heiß geliebtes, aber viel genutztes Austauschformat. Für Perl gibt es sehr viele Erweiterungen, um bequem in diesem Datenmeer zu fischen. Der heutige Snapshot diskutiert Vor- und Nachteile der gängigen XML-Module — das jeweils zweckmäßigste ist dann schnell gefunden.

871

Seinem inoffiziellen Leitspruch bleibt Perl auch treu, wenn es um das Verarbeiten von XML-Dokumenten geht: There is more than one way to do it - es gibt mehr als einen Weg für diese Aufgabe. Die verschiedenen Module sollen anhand des Beispiels von Abbildung 1 illustriert werden. Das File enthält zwei Datensätze vom Typ »<cd>« in einem »<result>«-Tag. Jeder dieser Datensätze besteht seinerseits aus Tags für »<artists>« und »<title>« einer CD, wobei »<artists>« wiederum ein oder mehrere »<artist>«-Tags umschließen darf.

Schnell, einfach und auf einen Rutsch

Am einfachsten parst sich XML in Perl mit Hilfe des Moduls XML::Simple vom CPAN. Dieses Modul exportiert die Funktion »XMLin«, die eine komplette Datei oder einen String mit XML-Daten hereinholt und anschließend als Datenstruktur in Perl ablegt:

use XML::Simple;
my $ref = XMLin("data.xml");


Abbildung 2 zeigt einen Dump der resultierenden Datenstruktur in »$ref«. Zwei Dinge fallen auf: Abhängig davon, ob ein oder zwei Künstler in »<artists>« stehen, ist die resultierende Datenstruktur entweder ein Skalar oder ein Array. Das erschwert später die Arbeit.

Mit der Option »ForceArray« lässt sich jedoch festlegen, dass ein Feld immer als Array dargestellt wird. Der Aufruf »XMLin("data.xml", ForceArray => [\'artist\']);« stellt sicher, dass »$ref->{cd}->[0]->{artists}->{artist}« ebenfalls eine Arrayreferenz zurückgibt, obwohl dort nur ein einziger Interpret steht.

Außerdem ist »->{artists}->{artist}« etwas umständlich zu schreiben, da »->{artists}« außer »->{artist}« keine weiteren Unterelemente enthält. XML::Simple bietet mit der »GroupTags«-Option die Möglichkeit, Hierarchien kollabieren zu lassen. Der Aufruf

XMLin("data.xml",
  ForceArray => ['artist'],
  GroupTags  =>
    {'artists' => 'artist'});


erzeugt die Datenstruktur in Abbildung 3, die schon sehr einfach zu handhaben ist. Beispielsweise lassen sich alle Seriennummern nun mit einer einfachen For-Schleife finden:

for my $cd (@{$ref->{cd}}) {
    print $cd->{serial}, "n";
}


XML::Simple liest die komplette XML-Datei in den Hauptspeicher ein, was oft praktisch ist, manchmal aber auch zum Problem wird: Bei riesigen XML-Dateien ist das nicht effizient oder schlichtweg unmöglich.

Verschlungene Pfade

Wer auf knapper und griffiger Notation besteht, um durch den XML-Dschungel zu navigieren, wird XPath lieben. Das Modul XML::LibXML vom CPAN hängt sich an die Libxml-2-Bibliothek des Gnome-Projekts an und bietet über die »findnodes«-Methode auch die Möglichkeit, per XPath-Notation auf XML-Elemente zuzugreifen.

Um zum Beispiel den Textinhalt aller »<title>«-Elemente zutage zu fördern, genügt die XPath-Notation »/result/cd/title/text()«, die mit »/« an der Dokumentenwurzel anfängt, in die »<results>«-, »<cd>«- und »<title>«-Elemente hinabsteigt und mit »text()« deren Textinhalt zurückgibt.

Abbildung 1: Der XML-Beispieldatensatz, der die hier vorgestellten XML-Module illustriert, zeigt ein CD-Archiv.

Alternativ geht es auch mit »//title/text()«, denn so stöbert XPath einfach alle »<title>«-Elemente in beliebiger Tiefe auf. Listing 1 zeigt, dass die Methode »findnodes()« eine Reihe von Textobjekten zurückgibt, deren Methode »toString()« den Titeltext liefert.

Aber mit XPath lassen sich auch wesentlich komplexere Aufgaben lösen: Listing 2 fieselt beispielsweise die Seriennummern aller CDs heraus, bei denen das Artist-Tag den String »Foo Fighters« enthält. Das leistet ein einzelnes, zunächst recht kompliziert wirkendes Konstrukt: »/result/cd/artists/artist[.="Foo Fighters"]/../../@serial«. Der Ausdruck wird verständlich, wenn man ihn abschnittweise betrachtet.

Zuerst steigt XPath bis zu den »<artist>«-Tags hinab und prüft dann jedes mit »[.="Foo Fighters"]«. Dieses in eckige Klammern eingeschlossene Prädikat referenziert mit ».« den aktuellen Knoten und kontrolliert, ob dessen Wert auch mit dem gesuchten String »Foo Fighters« übereinstimmt.

Trifft dies zu, fährt XPath mit »../..« anschließend zwei Etagen hoch. Auf dieser Ebene findet sich auch das CD-Tag. Dessen Parameter »serial« liest das Modul mittels »@serial« aus und gibt ihn zurück. Das Listing 2 »xpserial« muss dann nur noch die »value()«-Methode des zurückgelieferten Objekts bemühen, um den Wert des Parameters zu erhalten - in diesem Fall also die gesuchte Seriennummer der CD.

XPath erlaubt sehr prägnante und bündige Formulierungen. Doch sobald etwas nicht auf Anhieb funktioniert, kann die Fehlersuche viel Zeit verschlingen. Glücklicherweise bügelt Perl manchen Nachteil einer reinen XSLT-Umgebung wieder aus, weil es schnelle XPath-Hacks mit solider Programmlogik und seinen ausgezeichneten Debugging-Möglichkeiten kombiniert.

Listing 1:
»xptitles«

01 #!/usr/bin/perl -w
02 use strict;
03 use XML::LibXML;
04 
05 my $x = XML::LibXML->new() or
06     die "new failed";
07 
08 my $d = $x->parse_file("data.xml") or
09     die "parse failed";
10 
11 my $titles =
12     "/result/cd/title/text()";
13 
14 for my $title ($d->findnodes($titles)) {
15     print $title->toString(), "n";
16 }

Listing 2:
»xpserial«

01 #!/usr/bin/perl -w
02 use strict;
03 use XML::LibXML;
04 
05 my $x = XML::LibXML->new() or
06     die "new failed";
07 
08 my $d = $x->parse_file("data.xml") or
09     die "parse failed";
10 
11 my $serials = q{
12     /result/cd/artists/
13     artist[.="Foo Fighters"]/
14     ../../@serial
15 };
16 
17 for my $serial ($d->findnodes($serials)) {
18     print $serial->value(), "n";
19 }

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Perl-Snapshot

    Open Office hilft mit einer Vielzahl vorkonfigurierter Formate beim Ausdrucken von selbstklebenden Etiketten. Perl speist die dazu erforderlichen Adressdaten ins Dokument ein.

  • Überall Musik

    Das Modul Apache::MP3 baut eine komfortable Web-Jukebox um lose MP3-Sammlungen. Ein zusätzliches Perl-Skript macht die Songauswahl für den Musikliebhaber noch komfortabler.

  • Objekte statt Tabellen

    In objektorientiertem Programmcode wirken SQL-Abfragen wie Fremdkörper. Zudem unterscheiden sich die SQL-Dialekte verschiedener Datenbanken. Die Lösung: Der Objekt-Relational-Mapper SQL Object stellt ein einheitliches objektorientiertes Interface zur Verfügung.

  • Hinterm Horizont

    Der naturverbundene Perl-Hacker erforscht die Bergwelt selbstverständlich mit einem Navigationssystem. Dass er anschließend seine erbrachte Wanderleistung grafisch auswertet, ist Ehrensache.

  • Appetithäppchen

    Newsticker, Web-Blogs und andere Informationssysteme verwenden gerne das RSS-Format, um kurze Nachrichten in standardisierter Form an die Interessenten zu verteilen. Diese News-Schnipsel lassen sich bestens mit Tcl und der objektorientierten Erweiterung CZRSS verarbeiten.

comments powered by Disqus

Ausgabe 08/2016

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.