Werbung einblenden Werbung ausblenden


Home / Tutorials / Perl Handbuch / Übergabe der Usereingaben

Reports erstellen
die Datensätze in den Report einfügen
eine Überschrift definieren
aus unterschiedlichen Formaten zusammengesetzte Muster generieren
innerhalb der Formatdefinition Subroutinen aufrufen

Reports erstellen

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:

Macht insgesamt

26.50 €


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.

vorhergehendes Kapitel