Open Source im professionellen Einsatz

Newsletter abonnieren
Seite durchsuchen

HEFTARCHIV | NEWS | E-BIBLIOTHEK | VIDEO | BLOGS | WHITEPAPER | EVENTS | ACADEMY | ABO | SHOP

user friendly

  Home  »  Heft & Abo  »  Heftarchiv  »  2005  »  08  »  Datenfischer  

RSS-Feed der aktuellen News von Linux-Magazin Online Folgen Sie Linux-Magazin Online auf Twitter
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark

XML-Parser für Perl im Vergleich

Datenfischer

von Michael Schilli
Erschienen im Linux-Magazin 2005/08

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.

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 }
Diesen Artikel druckenDiesen Artikel weiterempfehlen Diesen Artikel kommentieren Newsletter abonnieren
Share/Bookmark
Ähnliche Artikel
Ready, Set, Go! Google erfindet neue Programmiersprache
Appetithäppchen RSS-Newsfeeds lesen mit Tcl, Snit und TDOM
Heilig nach Punkten Messenger-Plugin verschafft Vorteil durch Webseiten-Überwachung
Laufzeit-Tacho Profiler identifizieren Flaschenhälse in Perl-Programmen
Überall Projekte Skript managt Git-Repositories mit Metaverzeichnis
Ozapft is Yahoo-Dienste für eigene Skripte verwenden
Whitepaper
Daten Migration - Eine Publikation von Bloor Research

Datenmigrationsprojekte überschreiten häufig das Budget, neigen zu Verzögerung und werden unter Umständen komplett abgebrochen. Bloor Research ist eines der weltweit führenden IT-Forschungs-, Analyse- und Beratungsunternehmen und wird in dem vorliegenden White Paper die wichtigsten Aspekte dieser Problematik näher beleuchten. Ferner werden praktische Empfehlungen für erfolgreiche Migrationsprojekte gegeben, die Sie auf Ihr nächstes Projekt übertragen können.

Download PDF (Registrierung erforderlich)
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele

Über die letzten Jahre hinweg haben sich Open Source Lösungen als fester Bestandteil des gesamten Datenintegrationsmarktes etabliert. Viele Unternehmen haben bereits das Open Source Modell für Ihre Datenintegrationsprojekte aufgegriffen. Das vorliegende White Paper illustriert anhand ausgewählter Fallstudien und Anwendungsbeispiele die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.

Download PDF (Registrierung erforderlich)
Kommentare (0)