XML ist simpel mit XML::Simple

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

Es gibt Leute, die XML für die Erfindung eines krankhaften Geistes halten, der vermutlich die Ausrottung der Menschheit als Ziel hat. Man kann es manchmal verstehen. Der eingebettete Markup mit den Kleiner- und Größer-Zeichen und den Schrägstrichen ist nicht gerade eine Wohltat für die Augen. Nehmen wir die Verschachtelung von Elementen, die Knotentypen und DTDs (die doch so wohltuend einfach waren, verglichen mit XML-Schema) dazu, dann möchte man doch den Zeiten der CSV-Dateien (Comma Separated Values, eine Zeile ist ein Datensatz, die einzelnen Spalten werden durch ein festes Trennzeichen markiert) und ihres Parsers, der split -Funktion, nachtrauern.

Wir verraten Ihnen ein Geheimnis: Programme zur Verarbeitung von XML zu schreiben ist gar nicht so schwer. Ein ganzer Koffer voller Werkzeuge steht bereit, die einem die unzähligen lästigen Details des Parsers und des Aufbaus einer Datenstruktur abnehmen, mit einfachen, in Minuten verständlichen APIs. Wenn man die Komplexität einer XML-Anwendung mit allem Drum und Dran tatsächlich braucht, dann kann man sie haben, aber man muß eben nicht. Der Umgang mit XML kann ebenso einfach wie tiefgründig sein, je nach Anwendung. Für einfache Aufgaben gibt es auch einfache Werkzeuge.

Um das zu demonstrieren, wollen wir uns ein sehr einfaches Modul namens XML::Simple von Grant McLean anschauen. Mit minimalem Einarbeitungsaufwand läßt sich ein überraschend großer Erfolg bei der Verarbeitung von XML erzielen.

Ein typisches Programm liest ein XML-Dokument, ändert etwas und schreibt das Ergebnis zurück in eine Datei. Genau für diesen Prozeß ist XML::Simple gemacht. Ein einzelner Funktionsaufruf liest ein XML-Dokument und legt es in Form verschachtelter Hashtabellen im Hauptspeicher ab. Die Elemente und Daten werden durch die Hashtabellen repräsentiert. Nachdem man die gewünschten Änderungen vorgenommen hat, ruft man eine andere Funktion auf und schreibt das Ergebnis in eine Datei.

Probieren wir es aus. Wie bei jedem Modul müssen wir XML::Simple zunächst mit Hilfe von use in unser Programm laden:

 use XML::Simple; 

Durch den Aufruf hat XML::Simple die beiden folgenden Funktionen für uns definiert:

XMLin( )

Diese Funktion liest ein XML-Dokument aus einer Datei oder einem String und baut eine Datenstruktur auf, die die Daten und Elemente des XML-Dokuments enthält. Das Ergebnis der Funktion ist diese Datenstruktur in Form einer Hashreferenz.

XMLout( )

Bekommt eine Hashreferenz mit einem codierten Dokument übergeben und wandelt diese in korrekten XML-Markup um. Das Ergebnis der Funktion ist ein Textstring mit dem umgewandelten XML-Dokument.

Natürlich kann man nach Wunsch das Dokument auch von Grund auf neu aufbauen, indem man einfach mit Hilfe von Hashes, Arrays und Strings die entsprechenden Datenstrukturen »von Hand« aufbaut. Wenn man z. B. eine Datei zum ersten Mal erzeugt, dann mag das sogar erforderlich sein. Das ist kein Problem, nur zirkuläre Referenzen sollten vermieden werden. Andernfalls wird das Modul nicht richtig funktionieren.

Nehmen wir beispielsweise an, unser Boß möchte E-Mail an eine Gruppe von Personen schicken. Zu diesem Zweck könnte er den SpamChucker von WarbleSoft, eine bekannte Anwendung zur Verwaltung von Mailinglisten, benutzen. Der SpamChucker besitzt unter anderem die Fähigkeit, XML-Dateien zu importieren oder zu exportieren, die Listen von Mailadressen enthalten. Ein Boß hat Sonderwünsche, und so ist das auch in unserem Fall: Die Kundennamen sollen in Großbuchstaben geschrieben sein. Gebraucht wird also ein Programm, das eine XML-Datei liest, die Namen in Großbuchstaben umwandelt und die geänderte Datei dann wieder abspeichert.

Wir nehmen die Herausforderung an und betrachten zunächst einmal die XML-Datei, um ihre Struktur zu verstehen. Im folgenden Beispiel sehen wir eine solche Mailingliste.

Beispiel: XML-Dokument mit Mailingliste des SpamChucker

<?xml version="1.0" encoding="ISO-8859-1"?>
<spam-document version="3.5" timestamp="2002-05-13 15:33:45">
  <!-- Automatisch erzeugt durch WarbleSoft Spam Version 3.5 -->
  <customer>
    <first-name>Johannes</first-name>
    <surname>Jäger</surname>
    <address>
<street>Murmelstr. 17</street>
<city>Metzingen</city>
<state>Baden-Württemberg</state>
<zip>72555</zip>
</address>
    <email>jjaeger@gmx.de</email>
    <age>42</age>
  </customer>
  <customer>
    <first-name>Henrietta</first-name>
    <surname>Kittinger</surname>
    <address>
<street>Ermsstr. 2</street>
<city>Eningen</city>
<state>Baden-Württemberg</state>
<zip>72800</zip>
</address>
    <email>kitty@web.de</email>
    <age>37</age>
  </customer>
</spam-document>

Nach einem kurzen Blick in die Dokumentation von XML::Simple ( perldoc XML::Simple ) fühlen wir uns in der Lage, das im Beispiel unten gezeigte Skript zu verfassen:

Beispiel: Skript zur Umwandlung von Kundennamen in Großbuchstaben

# Dieses Programm liest eine vom WarbleSoft SpamChucker generierte XML-Datei
# und wandelt die Kundennamen in Großbuchstaben um.

# Schalten wir "strict" und "warnings" an, das ist nie ein Fehler.
use strict;
use warnings;

# Import des Moduls XML::Simple
use XML::Simple;

# Die Funktion "XMLin", die von XML::Simple zur Verfügung gestellt wird,
# wandelt die XML-Datei "./kunden.xml" in eine Hashreferenz um.
# Wir verwenden die Option "forcearrays", d.h., Elemente werden immer als Arrayreferenzen
# dargestellt. (Standardmäßig geschieht das nur, wenn sie mehrfach vorkommen.)
my $cust_xml = XMLin('./kunden.xml', forcearray=>1);

# In einer Schleife suchen wir die verschiedenen 'customer'-Elemente, die ihrerseits
# wieder Hashreferenzen sind und als Arrayreferenz unter dem Schlüssel 'customer'
# zu finden sind.
for my $customer (@{$cust_xml->{customer}}) {
# Der Inhalt von 'first-name' und 'surname' wird in Großbuchstaben umgewandelt.
# Das geht sehr einfach mit der in Perl eingebauten Funktion uc( ).
foreach ($customer->{'first-name'}, $customer->{'surname'}) {
$_->[0] = uc($_->[0]);
}
}

# Gib die Hashreferenz wieder als XML-Dokument auf den Bildschirm aus, sinnvollerweise
# schließen wir das Ganze mit einem Zeilenende ab.
print "<?xml version='1.0' encoding='ISO-8859-1'?>\n";
print XMLout($cust_xml);
print "\n";

Wenn wir dieses Programm laufen lassen (etwas leichtsinnig, da die ausgegebenen Daten ja eigentlich Sache unseres Chefs sind), dann bekommen wir diese Ausgabe:

<?xml version='1.0' encoding='ISO-8859-1'?>
<spam-document version="3.5" timestamp="2002-05-13 15:33:45">
  <customer>
    <address>
<state>Baden-Württemberg</state>
<zip>72555</zip>
<city>Metzingen</city>
<street>Murmelstr. 17</street>
</address>
    <first-name>JOHANNES</first-name>
    <email>jjaeger@gmx.de</email>
    <surname>JÄGER</surname>
    <age>42</age>
  </customer>
  <customer>
    <address>
<state>Baden-Württemberg</state>
<zip>72800</zip>
<city>Eningen</city>
<street>Ermsstr. 2</street>
</address>
    <first-name>HENRIETTA</first-name>
    <email>kitty@web.de</email>
    <surname>KITTINGER</surname>
    <age>37</age>
  </customer>
</spam-document>

Herzlichen Glückwunsch! Sie haben Ihr erstes Programm zur Verarbeitung von XML-Daten geschrieben, und es läuft hervorragend. Na ja, beinahe hervorragend. Die Ausgabe ist ein kleines bißchen anders als erwartet. Zum einen ist die Reihenfolge der Elemente verändert, da Hash-Arrays die Reihenfolge der eingefügten Schlüssel nicht erhalten. Außerdem sind die zwischen den einzelnen Elementen stehenden Einrückungen möglicherweise verlorengegangen. Kann das ein Problem sein?

Damit sind wir an einem interessanten Punkt angekommen, der uns immer wieder beschäftigen wird. Einfachheit und Vollständigkeit sind widersprüchliche Ziele. Als Entwickler müssen Sie selbst entscheiden, welche Teile Ihres Markups exakt sein müssen und welche nicht. Manchmal wird die Reihenfolge der Elemente wichtig sein, in diesem Fall kann man nicht mit XML::Simple arbeiten. Möglicherweise sollen auch Steueranweisungen (PIs oder Processing Instructions) erhalten bleiben, auch dies ein Fall, in dem XML::Simple ausscheidet. Man muß also die eingesetzten Module genau kennen und wissen, was sie können und was nicht. Die Entscheidung über die Werkzeuge muß wohlgemerkt schon vor der Programmierung fallen. In unserem Fall haben wir natürlich die veränderte Datei mit SpamChucker ausprobiert, alles lief hervorragend, und der Chef war glücklich. Das erzeugte Dokument kommt dem Original ausreichend nahe, um die Anforderungen der Anwendung zu erfüllen.

Man ist geneigt zu sagen, daß die durch uns vorgenommenen Änderungen ein semantisch äquivalentes Dokument erzeugt haben, aber das ist nicht ganz richtig. Die Reihenfolge der Elemente ist in XML im allgemeinen von Bedeutung. Wir haben lediglich das Glück, in diesem Fall eine großzügige Anwendung und einen ebenso großzügigen Endanwender zu haben, deren relativ geringe Anforderungen erfüllt sind.

Betrachten Sie sich selbst als Menschen, der mit XML und Perl umgehen kann!

Natürlich sind wir erst am Beginn unserer Reise. Der Großteil des Buchs liegt vor uns, voller Tips und Techniken, die beim Umgang mit XML hilfreich sein werden. Nicht alle Aufgaben zum Thema XML sind so einfach wie die eben gezeigte. Aber nichts ist so komplex oder schwierig, daß der Hammer Perl nicht genügen würde, um das Eisen XML damit zu schmieden.

  

  

<< 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