Werbung einblenden Werbung ausblenden


Home / Tutorials / Perl Handbuch / Übergabe der Usereingaben

das Modul XML::Parser

mit einem Perl Programm eine XML Datei so darstellen, wie die Originaldatei
eine Referenz auf eine Subroutine übergeben
über einen eventorientierten Ansatz eine XML Datei in eine HTML Datei konvertieren

das Modul XML::Parser

Wir beschreiben hier nur den eventorientierten Ansatz zur Verarbeitung von XML Dokumenten. Informationen zu DOM, XSL, XPATH und die wie diese Technologien mit Perl zusammenarbeiten finden Sie im Handbuch zu XML siehe link zum XML Handbuch

Wir gehen jetzt von dem XML Dokument aus, das wir im Kapitel Kurzeinführung in XML erstellt haben:

<personendaten>
<persona><name>Andres Ehmann</name>
<telefon>03047301388 </telefon>
<beruf>Diplom Volkswirt / Magister Artium</beruf>
<adresse>Hallandstrasse 2, 13189 Berlin</adresse>
</persona>
<persona>
<name>Manuel Landivar</name>
<telefon>03045654566</telefon>
<beruf>Licenciado en letras</beruf>
<adresse>Schonhauser Allee 23, 13178 Berlin</adresse>
</persona>

<persona><name>Maria Sedlemayer</name>
<telefon>089 49499444</telefon>
<beruf>Rechtanwältin</beruf>
<adresse>Krumme Strasse 5, 456545 Muenchen</adresse>
</persona>
<persona><name>Suleika Isnegrim</name>
<telefon>07623 555844 </telefon>
<beruf>Zahnärztin</beruf>
<adresse>Krozinger Strasse 12, 7867 Freiburg</adresse>
</persona>
</personendaten>

Dieses Dokument wollen wir jetzt mit einem eventorientierten Ansatz auswerten. Es ist vielleicht nicht der leistungsfähigste Ansatz, dafür aber ein sehr verständlicher Ansatz.
Eventorientiert heißt, dass das Perl Skript nach Ereignissen sucht. Das sind in diesem Zusammenhang: ein öffnender Tag, der Inhalt des Tags und ein schließender Tag. Hierfür wird das Perl Modul XML::Parser verwendet. Dieses Modul ist ein fester Bestandteil der ActiveState Distribution. Es muss also nicht mit dem Perl Packet Manager, siehe Arbeiten mit Modulen, eingebunden werden. Wer das Problem für trivial hält und der Meinung ist, das kann auch ohne ein Modul mit den Regular Expression funktionieren, der irrt. Der XML::Parser, der selbst auf expat aufbaut, liest das Dokument in lightning speed, so dass auch sehr große Dokumente verarbeitet werden können. Es ist eine andere Kategorie wie das Auslesen eines Flatfiles.
Ein Skript, welches das XML Dokument ausliest, wird in diesem Kapitel vorgestellt. (Ein Beispiel für Objektorientierte Programmierung )
mit einem Perl Programm eine XML Datei so darstellen, wie die Originaldatei

Zuerst kommt ein Beispiel, das lediglich die Datei so wieder auf den Schirm setzt, wie sie am Anfang aussah. Anschließend folgt ein komplexeres Beispiel, das tatsächlich eine Transformation nach HTML vornimmt:


#!/usr/bin/perl
use XML::Parser;
my $zeiger = new XML::Parser ();

$zeiger->setHandlers (Start => \&anfang,End => \&ende,Char=>\&inhalt );

$zeiger->parsefile ("test.xml");

sub anfang 
{
  $wert_des_zeigers  = shift;
   $starttag= shift;
    print "<$starttag>";
  print "\n";
}
sub ende
 {
  ($wert_des_zeigers,$endtag) = @_;
  print "</$endtag>\n";
}
sub inhalt 
{
($wert_des_zeigers,$inhalt)=@_;
print " $inhalt";
}

Um das Skript zum Laufen zu bringen, müssen sich beide Dateien in einem Ordner befinden. Die XML Datei sollte hierbei text.xml heißen, weil das Perl Skript nach einer solchen Datei sucht.

$zeiger->parsefile ("test.xml");

Dieses Skript verwendet das Modul XML::Parser (das Modul XML und davon den Package Parser).
Dieses Modul wird mit use in das Programm eingebunden. (Unterschied do, require, use siehe Auslagern von Programmen mit use):

use XML::Parser

Anschließend wird von dem Package XML::Parser ein Objekt gebildet (Objektorientierte Programmierung)
Etwas ungewöhnlich ist hier die Zeile:

my $zeiger
= new XML::Parser ();


Das ist aber das gleiche wie das bereits bekannte

my $zeiger=XML::Parser ->new();

$zeiger ist jetzt also eine Referenz auf "ein Dingsda", wahrscheinlich auf einen anonymous Hash, weil die nächste Zeile einen Hash übergibt. Dieses "referenzierte Dingsda", wir erinnern uns (Objektorientierte Programmierung), ist verknüpft mit dem Package XML::Parser.
Die nächste Zeile ist ebenfalls eigentümlich.

$zeiger->setHandlers
(Start => \&anfang,End => \&ende,Char=>\&inhalt );

Eigentümlich ist die Parameterübergabe: Übergeben wird ein Hash mit Start, End, Char als Schlüssel und Referenzen auf die Funktion anfang ,ende, inhalt als Wert.
An einem weiteren Beispiel kann man sich klarmachen, wie dies funktioniert:


#!/usr/bin/perl

testen("Ehmann"=>"Andres","Maier"=>"M&uuml;ller","Binsengr&uuml;n"=>"Igor");
sub testen
{
%banane=@_;
foreach (keys(%banane))
{
  print "Nachname ist $_ und Vorname ist $banane{$_} \n";
}
}

<strong>%banane=@_;</strong>

Der Sonderarray @_, der also aussieht wie ein Array, kann offensichtlich auch Hashes "verarzten". Das heißt, auf die oben dargestellte Weise kann ein Hash vollständig übergeben werden.
Bei Referenzen wurde schon angedeutet, das nicht nur eine Referenz auf eine Variable, einen Hash und einen Array gebildet werden kann, sondern auch auf eine Subroutine.
Mit der folgenden Zeile fangen wir an, das XML Dokument, in unserem Falle also test.xml, auszuwerten.

$zeiger->parsefile ("test.xml");

Beim Auswerten stößt der XML Parser auf öffnende Tags, auf schließende Tags und auf den eigentlichen Inhalt zwischen den Tags:

<irgendwas>
</irgendwas>

Stößt der XML Parser auf einen öffnenden Tag, ruft er die Funktion anfang auf und übergibt zwei Parameter, erstens den Namen des $zeigers (das referenzierte Dingsda, das weiß zu wem es gehört) und den Tag, den er gefunden hat.
Der Zeiger interessiert uns nicht. Wir eliminieren ihn mit shift aus dem Sonderarray @_. Der Tag interessiert uns. Wir begrenzen mit den Tag Zeichen und setzen ihn auf den Schirm.

Nachdem der XML Parser einen öffnenden Tag gefunden hat, findet er auch den Inhalt. Folglich wird die Subroutine Inhalt aufgerufen, der wiederum zwei Parameter übergeben werden: der Zeiger, der mit shift eliminiert wird, und der Inhalt, den wir auch ausdrucken.
Das gleiche passiert mit den schließenden Tags.

Wir erhalten also das Original Dokument auf dem Schirm. Zugeben, das ist noch nicht besonders aufregend. Wie das Dokument aussieht, wussten wir schon vorher.
Die gleiche Technik kann aber genutzt werde, um ein XML Dokument in ein HTML Dokument zu konvertieren. Vorher machen wir uns aber noch mal klar, wie der Aufruf der Subroutinen anfang, inhalt und start aus dem Objekt heraus erfolgt, bzw. wie er erfolgen könnte.

eine Referenz auf eine Subroutine übergeben

Das unten stehende Programmschnipsel dient lediglich der Illustrierung, wie eine Referenz auf eine Subroutine übergeben werden kann.

package test; sub new { $zeiger={};
bless($zeiger); } sub create_love { $zeiger=shift; %werte=@_;
while(($schluessel,$wert)=each(%werte)) { &$wert("$schluessel");
} } sub hello { print "Hallo $_[0] \n"; } sub how_do_you_do
{ print "Ist dein Name $_[0] ?"; } $love=test-> new(); $love->create_love("Knopf"=>\&hello,"Shokufeh"=>\&how_do_you_do);


Entscheidend ist die folgende Zeile. Hier wird mit der gleichen Syntax, wie in dem Beispiel oben, eine Referenz auf eine Subroutine und ein Wert übergeben:


$love->create_love("Knopf"=>\&hello,"Shokufeh"=>\&how_do_you_do);

Diese Variablen werden an die Subroutine create_love übergeben, allerdings nicht als Werte des Objektes, sondern als globale Variablen. In der folgenden Zeile sehen wir uns wieder mit der Tatsache konfrontiert, dass @_ erst mal den Zeiger auf das Objekt überträgt, den wir mit shift in die Variable $zeiger stecken, und dann wird noch einen Hash "Knopf"=>\&hello,"Shokufeh"=>\&how_do_you_do) übertragen, den wir in den Hash %Werte packen:

$zeiger=shift; %werte=@_;

In der while Schleife rufen wir dann über die Referenz auf die Subroutine, die Subroutine auf und übergeben den Schlüssel des Hashs als Parameter.

über einen eventorientierten Ansatz die XML Datei in eine HTML Datei konvertieren

Jetzt kommt ein Perl Skript, das tatsächlich mit eventorientiertem Ansatz die XML Datei in eine HTML Datei konvertiert:

#!/usr/bin/perl

print "Content-type:text/html\n\n";

use XML::Parser;
my $zeiger = new XML::Parser ();

$zeiger->setHandlers (
Start => \&anfang,
End => \&ende,Char=>\&inhalt );
$zeiger->parsefile ("test.xml");

print "<html><head><body>";

sub anfang
{
%watnu1=("persona"=>"<table border=1 bgclor=yellow>","name"=>
"<tr><td>","telefon"=>"<td>","beruf"=>"<td>","adresse"=>"<td>");
$wert_des_zeigers = shift;
$starttag=shift;
print $watnu1{$starttag};
print "\n";
}

sub ende
{
%watnu2=("persona"=>"</table>","name"=>
"</td>","telefon"=>"</td>","beruf"=>"</td>","adresse"=>"</td></tr>");
($wert_des_zeigers,$endtag) = @_;
print "$watnu2{$endtag}";
}

sub inhalt
{
($wert_des_zeigers,$inhalt)=@_;
print " $inhalt";
}

print "</body></html>";

Das Programm hat, bis auf einige kleine Änderungen, den gleichen Aufbau, wie das erste Programm.
Es kann, wie gewohnt, mit der Eingabeaufforderung (Dos Box) aufgerufen werden. Ein Aufruf im Browser ist ebenfalls möglich, was hier natürlich mehr Sinn macht, denn in der Dos Box sind nur die HTML Tags sichtbar. Sie können aber nicht interpretiert werden. Für den Aufruf im Browser werden beide Dateien, sowohl das Perl Programm als auch die XML Datei im cgi-bin Verzeichnis gespeichert.
Der Aufruf erfolgt dann nach dem üblichen Schema: http://127.0.0.1/cgi-bin/mein_Skriptname.pl.
Wir sehen dann, dass für jeden Datensatz eine eigene Tabelle generiert wird. (eine Tabelle wird für das generiert, was zwischen folgenden Tags steht)

<persona> </persona>

Das wurde erreicht indem folgende Änderungen vorgenommen wurden:

der Subroutine anfang wurde dieser Hash hinzugefügt
%watnu1=("persona"=>"<table border=1 bgclor=yellow>","name"=>"
<tr><td>","telefon"=>"<td>","beruf"=>"<td>","adresse"=>"<td>");

und bei der Subroutine ende dieser

%watnu2=("persona"=>"</table>","name"=>
"</td>","telefon"=>"</td>","beruf"=>"</td>","adresse"=>"</td></tr>");

Nachdem das Objekt $zeiger die Subroutine parsefile aufgerufen hat, parst diese die Datei test.xml.
Wenn sie einen öffnenden Tag findet, ruft sie die Subroutine anfang auf und übergibt zwei Parameter, den Zeiger auf das Objekt, das sie aufgerufen hat, in diesem Falle $zeiger, und den Tag, den sie gefunden hat.
Jedem XML Tag wiederum wurden über einen Hash eine Reihe von HTML Tags zugeordnet. Über diesen Hash wird nun ermittelt, welche HTML Tags gedruckt werden sollen, wenn der korrespondierende XML Tag übergeben wird. Diese HTML Tags werden dann gedruckt.
Stößt parsefile auf Inhalt, wird der Inhalt gedruckt. Das gleiche wie bei start passiert auch bei ende.
Wir verdeutlichen uns das Verfahren noch mal. Die Subroutine stößt nacheinander auf:

<personendaten> => keine Verknüpfung, nichts passiert
<persona> =><table border=1 bgcolor=yellow>
<name> =><tr><td>
Inhalt =>Andres Ehmann
</name> =></td>
<telefon> =><td>
Inhalt => 03047301388
</telefon> =></td>
<beruf> =><td>
Inhalt =>Diplom Volkswirt / Magister Artium
</beruf> =></td>
<adresse> =><td>
Inhalt =>Hallandstrasse 2, 13189 Berlin
</adresse> =></td></tr>
<persona> =></table>
   
etc.  

Wir sehen also links den Quellbaum, das XML Original Dokument und rechts den Ergebnisbaum, die transformierte Datei.

vorhergehendes Kapitel