
Reports erstellen
die Datensätze in den Report einfügen
eine Überschrift definieren
aus unterschiedlichen Formaten zusammengesetzte
Muster generieren
innerhalb der Formatdefinition Subroutinen
aufrufen
Perl heißt: practical extraction
and report language. Der extraction Teil wurden in dem
Kapitel Regular Expression schon behandelt. Es fehlt der Report
Teil. Report bedeutet, dass es in Perl möglich ist, Muster
(Templates) zu erstellen und in diese Muster zur Laufzeit
des Programms Werte einzulesen. Eine Anwendungen hierfür
ist z.B. das Erstellen von Rechnungen, statistischen Auswertungen
aus Massendaten, ect. Der Report Teil soll hier nur oberflächlich
behandelt werden, aus dem schlichten Grund, dass im CGI Umfeld
keine Probleme mit dem Report vorkommen.
Der einfachste aller möglichen Reports sieht so aus:
$nachname="Ehmann";
$vorname="Andrés";
$telefon="030-77301386";
format =
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
write();
Zu Beginn haben wir hier eine Variabelenzuweisung,
die nicht besonders erklärungsbedürftig ist. Dann
kommt das reservierte Wort format=. Dies bedeutet
für Perl: der Beginn des Musters, wobei der Punkt (.)
für Perl das Ende der Musterdefinition darstellt.
In der Musterdefinition haben wir die Platzhalter:
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
Die Platzhalter haben normalen Zeichenketten
dazwischen (Name, Vorname, Telefon). Innerhalb der Format
Definition gelten also andere Regeln:
-
Erstens werden Leerzeichen innerhalb
der Musterdefinition interpretiert.
-
Zweitens steht das @ Zeichen nicht mehr
für einen Array, sondern für den Beginn eines
Platzhalters für Variablen.
-
Drittens ist das < Zeichen kein mathematisches
"kleiner Zeichen", sondern steht für ein Zeichen.
Gibt es z.B. 10 mal <, dann dürfen 10 Zeichen
vorkommen. Ist die Variable, die für den Platzhalter
eingesetzt wird größer als 10 Zeichen, wird sie
abgeschnitten. Ist sie kürzer, wird mit Leerzeichen aufgefüllt.
In der nächsten Zeile stehen dann die Variablen, die
anstatt der Platzhalter eingesetzt werden sollen.
Werden also drei Platzhalter definiert, sind drei Variablen
notwendig:
$nachname, $vorname, $telefon
Die Variablen müssen natürlich irgendwo
im Programm einen Wert bekommen haben, entweder durch eine
einfache Zuweisung, wie in diesem Beispiel, oder durch Auslesen
der Werte aus einer relationalen Datenbank, siehe Zugriff
auf relationale Datenbanken mit dem dbi Modul, oder aus
einer Flatfile Datenbank, siehe Arbeiten
mit Textdateien.
| die
Datensätze in den Report einfügen |
|
Die Art und Weise, wie die Variable in den Platzhalter
eingefügt wird, kann nun modifiziert werden. Die Werte
können linksbündig, rechtsbündig oder zentriert
eingefügt werden.
Ein Beispiel für rechtsbündiges Einfügen sieht
so aus:
$nachname="Ehmann";
$vorname="Andrés";
$telefon="030-77301386";
format =
Nachname @>>>>>>>>>>>>>>>> Vorname @>>>>>>>>>>>>> Telefon @>>>>>>>>>>
$nachname, $vorname, $telefon
.
write();
Ein Beispiel für zentriertes Einfügen:
$nachname="Ehmann";
$vorname="Andrés";
$telefon="030-77301386";
format =
Nachname @||||||||||||| Vorname @||||||||||||| Telefon @|||||||||||||
$nachname, $vorname, $telefon
.
write();
Das
sieht bis jetzt nicht besonders aufregend aus, da wir nur
einen Datensatz in den Report eingebunden haben. Selbstverständlich
können beliebig viele Datensätze eingebunden werden,
die normalerweise von irgendwelchen Datenbanken gezogen werden.
Damit das mit "paste and copy" einfacher ist, ziehen wir uns
die Werte jetzt aus einem Array mit Zeigern auf drei anonyme
Arrays:
@banane=(["Ehmann","Gonzales","Maier"],["Andres","Felipe","Peter"],
["030-47301388","050-4543355","089-74949355"]);
format =
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
foreach $i(0..$#{$banane[0]})
{
$nachname=$banane[0]->[$i];
$vorname=$banane[1]->[$i];
$telefon=$banane[2]->[$i];
write();
}
Wie die folgende Zeile ausgelesen wird, zeigt
das Kapitel Referenzen.
@banane=(["Ehmann","Gonzales","Maier"],["Andres","Felipe","Peter"],
["030-47301388","050-4543355","089-74949355"]);
Jetzt werden innerhalb der foreach Schleife hintereinander
die Datensätze eingelesen. Wir haben so einen zweidimensionalen
Array simuliert. Mit jedem neuen Wertesatz rufen wir das Muster
auf, so dass ein Datensatz nach dem anderen auf den Schirm
erscheint.
Das folgende Beispiel zeigt das gleiche Schema mit einer Flatfile
Datenbank.
Wir haben folgenden Flatfile, mit dem namen banane.tx.
Ehmann;Andrés;03047301388
Gonzales;Felipe;040-3453444
Maier;Peter;089-7494955555
open(kirsche,"banane.txt");
@kirsche=;
close(kirsche);
format =
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
foreach $i(0..$#kirsche)
{
($nachname,$vorname,$telefon)=split(";",$kirsche[$i]);
write();
}
Was das Auslesen von banane.txt angeht siehe
Arbeiten mit Textdateien.
| eine
Überschrift definieren |
|
Was macht man jetzt, wenn man über dem
ganzen noch eine Überschrift haben will?
Ehmann;Andrés;03047301388
Gonzales;Felipe;040-3453444
Maier;Peter;089-7494955555
open(kirsche,"banane.txt");
@kirsche=;
close(kirsche);
format =
Die Telefonummern meiner Kollegen:
------------------------------------------------------------------------
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
foreach $i(0..$#kirsche)
{
($nachname,$vorname,$telefon)=split(";",$kirsche[$i]);
write();
}
Bei dieser Variante würde vor jeden Datensatz
folgendes gedruckt: "Die Telefonnummern meiner Kollegen".
Dies ist definitiv nicht wünschenswert.
Eine Überschrift erhält man:
@banane=(["Ehmann","Gonzales","Maier"],["Andres","Felipe","Peter"],
["030-47301388","050-4543355","089-74949355"]);
format STDOUT_TOP=
Das sind die Telefonnummern meiner Kollegen
------------------------------------------------------------------------
.
format =
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
foreach $i(0..$#{$banane[0]})
{
$nachname=$banane[0]->[$i];
$vorname=$banane[1]->[$i];
$telefon=$banane[2]->[$i];
write();
}
Eine andere Schreibweise ist:
@banane=(["Ehmann","Gonzales","Maier"],["Andres","Felipe","Peter"],
["030-47301388","050-4543355","089-74949355"]);
format STDOUT_TOP=
Das sind die Telefonnummern meiner Kollegen
------------------------------------------------------------------------
.
format STDOUT =
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
foreach $i(0..$#{$banane[0]})
{
$nachname=$banane[0]->[$i];
$vorname=$banane[1]->[$i];
$telefon=$banane[2]->[$i];
write(STDOUT);
}
Wir haben zwei Formate:
format STDOUT_TOP= Das sind die Telefonnummern
meiner Kollegen ------------------------------------------------------------------------
. format STDOUT = Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<<
Telefon @<<<<<<<<<<<<< $nachname, $vorname, $telefon
Das erste Format definiert die Überschrift,
das zweite den eigentlichen Bericht.
Bei dem ersten Format fällt STDOUT_TOP auf. Unter _TOP
könnten wir uns noch etwas vorstellen. Das heißt
oben, also die Überschrift. STDOUT ist der Filehandle,
in den gedruckt wird. Das Format muss denselben Namen haben,
wie der Filehandle. Irritierend ist auch, dass das Format
STDOUT_TOP gar nicht explizit aufgerufen wird. Beachtlich
ist in diesem Zusammenhang, dass STDOUT_TOP nur aufgerufen
wird, wenn STDOUT mindestens einmal aufgerufen wird.
Wird die foreach Schleife so umgeschrieben, dass sie nicht
durchlaufen wird, z.B. bei 3 mal starten, dann erscheint auch
die Überschrift nicht. STDOUT ist der Default, so dass,
außer bei der Definition der Überschrift, STDOUT
nicht angegeben werden muss:
Drucken wir zum Beispiel nicht in den STDOUT,
sondern in den Filehandle einer Datei, sieht das so aus:
format banane_TOP =
Das sind die Telefonnummer meiner Kollegen
------------------------------------------------------------------------
.
@banane=(["Ehmann","Gonzales","Maier"],["Andres","Felipe","Peter"],
["030-47301388","050-4543355","089-74949355"]);
open(banane,">>meine_kollegen.txt");
format banane =
Nachname @<<<<<<<<<<<<< Vorname @<<<<<<<<<<<<< Telefon @<<<<<<<<<<<<<
$nachname, $vorname, $telefon
.
foreach $i(0..$#{$banane[0]})
{
$nachname=$banane[0]->[$i];
$vorname=$banane[1]->[$i];
$telefon=$banane[2]->[$i];
write(banane);
}
print "Heureka ! Jetzt werden die Daten sogar angefügt";
close(banane);
Das Format hat jetzt den Namen banane, und das
ist auch der Filehandle, in den gedruckt wird. Selbstverständlich
können auch Berichte an bestehende Berichte angefügt
werden, indem die Datei mein_kollegen.txt zum Anfügen
von Daten geöffnet wird.
open(banane,">>meine_kollegen.txt");
Im Hinblick auf die Kopfzeile ergibt sich kein Unterschied,
ob in den STDOUT oder in den Filehandle einer Datei gedruckt
wird.
Bis jetzt hatten wir nur den Fall, dass der
Platzhalter eine Variable aufgenommen hat. War sie zu lang,
wurde sie abgeschnitten, bzw. wäre abgeschnitten worden.
Was ist, wenn wir folgendes Beispiel haben wollen:
------------------------------------------------------------------------------
| Al Capone | Mieses Schwein. Blutrünstig |
| | und geldgeil. Absolut |
| | rücksichtslos |
|-----------------------------------------------------------------------------
|Maky Messer | Der Bandit mit dem seidenen |
| | Hemd. Baby Face. |
------------------------------------------------------------------------------
Wir
wollen also, dass sich eine Variable, von der wir unter Umständen
nicht wissen, wie lang sie ist, über mehrere Zeilen erstrecken
kann.
Das sieht dann so aus:
%banane=("Al Capone","Mieses Schwein, Blutrünstig und geldgeil. Absolut rüchsichtslols",
"Maky Messer","Der Bandit mit dem seidenen Hemd. Baby Face");
format STDOUT=
-------------------------------------------------
|^<<<<<<<<<<<<<< |^<<<<<<<<<<<<<<<<<<<<<<<<<<<~~|
$name, $beschreibung
-------------------------------------------------
.
foreach $himbeere(keys(%banane))
{
$name=$himbeere;
$beschreibung=$banane{$himbeere};
write(STDOUT);
}
| aus
unterschiedlichen Formaten zusammengesetzte Muster |
|
Es sind auch Fälle denkbar, bei deinen
ein Muster nicht ausreicht. Hier ein Beispiel:
Wir danken für Ihren
Besuch in "der Hirsch, der aus der Kälte kam" |
1
Flasche Bier |
3.50
€ |
2 Flaschne Whisky
|
20.00 € |
1000
Gehirnzellen |
3.00
€ |
|
Macht insgesamt |
26.50 € |
Wir haben nun ein Muster, dass sich aus drei
Formaten zusammensetzt. Einmal die Überschrift, dann
der Teil, der sich Daten dynamisch aus einer Datenbank zieht:
1
Flasche Bier |
3.50
€ |
2
Flaschne Whisky |
20.00 € |
1000
Gehirnzellen |
3.00 € |
und der Teil, der die Daten zusammenaddiert
und dann zusammenfasst:
Das lässt sich mit folgendem Programm
darstellen:
@speise_und_trank=([1,2,1000],["Flasche Bier","Flasche Whisky","Gehirnzellen"],["3.50","20","3"]);
format STDOUT_TOP=
Wir danken für Ihren Besuch in "der Hirsch der aus der Kälte kam"
.
format STDOUT=
@##### @<<<<<<<<<<<<<<<<<<<<< @####.## €
$zahl, $was,$preis
.
format STDOUT_GESAMT=
------------------------------------------------------------------------
Macht insgesamt @#####.##
$summe
.
foreach $i(0..$#{$speise_und_trank[0]})
{
$zahl=$speise_und_trank[0]->[$i];
$was=$speise_und_trank[1]->[$i];
$preis=$speise_und_trank[2]->[$i];
write();
$summe=$summe+$preis;
}
$~="STDOUT_GESAMT";
write();
In diesem Skript wird das Format geändert,
in dem $~ ein neuer Wert zugewiesen wird. In $~ schaut die
write Funktion nach einem Muster. Der Default ist der FILEHANDLE.
Man kann aber auch ein Format definieren nach dem Schema,
FILEHANDLE_EINS, FILEHANDLE_TOLL, ect.. FILEHANDLE_ muss aber
immer davor stehen, sonst weiß Perl nicht, was gedruckt
werden soll, da der Parameter bei der write Funktion angibt,
was gedruckt wird und wer.
Bis jetzt gab es keine Probleme, mit den einzusetzenden Variablen.
Sie kamen aus einer Datenbank und wurden unverändert
in das Muster eingesetzt.
| innerhalb
der Formatdefinition Subroutinen aufrufen |
|
Denkbar ist aber auch, dass die einzusetzenden
Werte von einer Subroutine errechnet werden:
Zahl Quadrat
2 4
8 64
3 9
Aus didaktischen Gründen
lösen wir das jetzt etwas umständlich:
@zahlen=(2,8,3);
format STDOUT_TOP=
Zahl Qudrat
------------------------------------------------------------------------
.
format STDOUT=
@##### @###########
$zahl,quadrate($zahl)
.
foreach $himbeere(@zahlen)
{
$zahl=$himbeere;
write(STDOUT);
}
sub quadrate
{
$summe=$_[0] * $_[0];
return $summe;
}
Wie deutlich zu
sehen ist, kann innerhalb der Definition des Formats auch
eine Subroutine aufgerufen werden, die die Werte berechnet.
|
 |