XML-basierte Programmierhilfen

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

Als nächstes wollen wir uns mit Software beschäftigen, die in einem gewissen Sinn das genaue Gegenstück zu dem ist, was wir soeben gesehen haben. Statt möglichst bequem und im Stil von Perl mit XML-Dokumenten zu arbeiten, wollen wir nun die XML-Standards einsetzen, um eine vorhandene Aufgabe zu vereinfachen, die an und für sich auch ganz gut ohne XML gelöst werden könnte. Erst vor relativ kurzer Zeit begab es sich, daß einige der Schlüsselfiguren der perl-xml -Mailing-Liste über eine Miniplattform für universelle Datenbehandlung in Perl diskutierten. Kern der Plattform sollte (aus Performancegründen) SAX sein. Aus dieser Diskussion sind einige sehr interessante und nützliche Beispiele entstanden, darunter XML::SAXDriver::Excel und XML::SAXDriver::CSV von Ilya Sterin und Matt Sergeants XML::Generator::DBI. Alle drei Module haben die Eigenschaft, ein fremdes Datenformat – Dateien von Microsoft Excel, CSV-Dateien (also Dateien mit festen Trennzeichen) und SQL-Datenbanken – zu nehmen und durch eine SAX-Schnittstelle elegant zu verpacken. Ein Beispiel dieses Vorgangs haben wir schon in SAX gesehen. Einem Programmierer bietet das die Illusion, die neuen Datenquellen seien ebenso einfach und leicht zu warten wie normale XML-Dokumente. (Welche Verrenkungen die zugrunde liegenden Module anstellen müssen, um diese Illusion zu bewirken, kümmert den Anwender nicht.)

Da das Thema tiefgreifende Auswirkungen auf die neueren Entwicklungen hat, wollen wir im folgenden auf eines dieser Module näher eingehen.

XML::Generator::DBI

XML::Generator::DBI ist ein wunderbares Beispiel eines Glue-Moduls (»Klebstoff«-Modul, man spricht wohl am besten von Middleware), einem einfachen Stück Software, dessen Aufgabe die Verbindung zweier an und für sich fremder, aber thematisch zusammenhängender Programme ist. In unserem Fall bedeutet das: Haben wir ein Objekt dieser Klasse erzeugt, dann können wir es zur Steuerung anderer Objekte einsetzen, in unserem Fall ein DBI-Datenbankhandle und ein SAX-ContentHandler.

XML::Generator::DBI versteht nichts davon, woher genau die Daten kommen, sondern verläßt sich einfach auf die Methodenaufrufe des jeweiligen Standards (sei es DBI, SAX oder SAX2). Wenn wir die execute-Methode des XML::Generator::DBI-Objekts mit einer normalen SQL-Anweisung als Argument aufrufen, verhält sich dieses, als sei es ein normales DBI-Datenbankhandle.

Das folgende Beispiel zeigt das Modul in Aktion. Der SAX-Handler ist in diesem Fall eine Instanz von Michael Koehnes XML::Handler::YAWriter, ein hervorragend konfigurierbares Modul, das SAX-Events in Text konvertiert. Mit Hilfe dieses Programms können wir zum Beispiel eine SQL-Tabelle mit CDs in wohlgeformtes XML konvertieren und dann das Ergebnis ausgeben lassen:

#!/usr/bin/perl

use warnings;
use strict;

use XML::Generator::DBI;
use XML::Handler::YAWriter;                      

use DBI;

my $ya = XML::Handler::YAWriter->new(AsFile => "-");
my $dbh = DBI->connect("dbi:mysql:dbname=test", "jmac", "");
my $generator = XML::Generator::DBI->new(
                      Handler => $ya,
                      dbh => $dbh
                      );
my $sql = "select * from cds";

$generator->execute($sql);

Das Ergebnis sieht in etwa so aus:

<?xml version="1.0" encoding="UTF-8"?><database>
    <select query="select * from cds">
        <row>
            <id>1</id>
            <artist>Donald and the Knuths</artist>
            <title>Greatest Hits Vol. 3.14159</title>
            <genre>Rock</genre>
        </row>
        <row>
            <id>2</id>
            <artist>The Hypnocrats</artist>
            <title>Cybernetic Grandmother Attack</title>
            <genre>Electronic</genre>
        </row>
        <row>
            <id>3</id>
            <artist>The Sam Handwich Quartet</artist>
            <title>Handwich a la Yogurt</title>
            <genre>Jazz</genre>
        </row>
    </select>
</database>

Das Beispiel ist für sich genommen noch nicht sehr interessant, sieht aber natürlich als Ausgabe schon einmal ganz gut aus. Der Witz ist, daß wir nicht unbedingt YAWriter als SAX-Handler benutzen müssen. Jedes andere SAX-Handlermodul würde es tun, insbesondere ein selbstgeschriebenes. Stellen wir uns dieselbe Datenbanktabelle wie oben vor. Wenn wir die execute-Methode des Objekts $generator aufrufen, würde sich diese exakt so verhalten, als hätte ein XML-Parser das obige Dokument gelesen (von den Leerzeichen einmal abgesehen, die YAWriter für die bessere Lesbarkeit einfügt) und Events für den SAX-Handler erzeugt. Es ist nicht zu unterscheiden, ob die Datenquelle ein XML-Dokument oder eine Datenbanktabelle ist.

Mehr zu DBI und SAX

Da wir gerade so schön dabei sind, sollten wir uns noch etwas mit dem Zusammenhang zwischen DBI und SAX beschäftigen. Beide haben mehr gemeinsam, als man auf den ersten Blick annimmt.

Der wesentliche Grund des Erfolgs von DBI in der Perl-Welt ist seine Architektur. Wenn man mit DBI arbeiten will, benötigt man für gewöhnlich zwei Softwarepakete: DBI.pm implementiert den äußeren Teil der DBI-Schnittstelle (und enthält natürlich die Dokumentation). Allerdings kann man mit DBI alleine keine Datenbank ansprechen. Man benötigt stets noch einen datenbankspezifischen Treiber, also das DBD-Modul. CPAN enthält eine reiche Auswahl an Treibern, unter anderem DBD::MySQL, DBD::Oracle oder DBD::Pg für Postgres. Der Anwendungsprogrammierer sieht nur das DBI-Modul, in das er seine SQL-Queries hineinsteckt und das ihm Ergebnistabellen liefert. Die Kommunikation mit der tatsächlichen Datenbank erledigt dagegen der Treiber im Auftrag von DBI. Zu diesem Zweck definiert DBI auch eine interne Schnittstelle, die nur die Autoren der Treiber kennen müssen und die immer noch datenbankunabhängig ist, allerdings auf viel niedrigerer Ebene. In der Theorie kann man damit letzten Endes ein Perl-Programm schreiben und durch einfachen Austausch des Treibers die Datenbank wechseln.

Anmerkung: Das setzt natürlich voraus, daß der Programmierer dafür sorgt, die proprietären Features einer bestimmten Datenbank nicht zu verwenden. $sth->query('select last_insert_id( ) from foo') funktioniert wunderbar mit einer MySQL-Datenbank, würde unseren Freunden, die PostgreSQL einsetzen, dagegen eher Schrecken einjagen. Zu diesem Thema gibt es einen ausgezeicheten Anhang in Programmierung mit Perl DBI von Alligator Descartes und Tim Bunce (O’Reilly Verlag).

Eine Bewegung in eine ähnliche Richtung findet zur Zeit in der Welt von Perl und XML statt. Was im Jahre 2001 mit den SAX-Generatoren begann, die wir am Anfang dieses Abschnitts vorgestellt haben, setzt sich mit dem XML::SAX-Modul fort. XML::SAX ist eine SAX2-Abstraktion, die sich ähnlich wie DBI verhält. Man verlangt einen SAX-Parser von dem Modul und man bekommt ihn. Dabei kann man obendrein noch alle möglichen Optionen angeben, die das Verhalten des gewünschten Parsers konfigurieren sollen: Automatisch wird ein passender gesucht, instanziiert und zurückgegeben. Man hängt einen beliebigen SAX-Handler an (analog zur Arbeit mit XML::Generator::DBI) und ist fertig.

Natürlich bietet XML::SAX keine Vielzahl von Datenbanktreibern, die aus beliebigen Datenbanken lesen. Das ist auch nicht nötig, denn dieses Thema wird ja schon von XML::Generator::DBI abgehandelt. Statt dessen gibt es eine Vielzahl von PerlSAX-Handlern, die Daten aus nahezu jeder beliebigen Datenquelle liefern können – ein DBI-Treiber ist nur ein Beispiel. Wie im Fall von DBI genügt ein wirklich fähiger Hacker, um ein für allemal ein Modul zum Zugriff auf die Daten zu implementieren – ab da entlockt das Thema allen anderen nur noch ein müdes Lächeln, da sie auf das Modul zurückgreifen können. Kenntnisse über die konkrete Datenquelle sind dabei nicht erforderlich, man muß lediglich mit SAX umgehen können, um das vormals fremde Format zu verarbeiten.

  

  

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