2 Man spricht populo

Die grundlegende Designentscheidung bei populo besteht darin, den diversen Zuständen der Suchmaschine nicht unterschiedliche Programme entsprechen zu lassen, in deren Programmcode Elemente der Avanti-Jobs und der HTML-Ausgabeseiten eingebettet sind, sondern Vorlagedateien für die Avanti-Aufträge und Ausgabeseiten, die von einem Programm interpretiert werden. Damit diese Interpretation stattfinden kann, ist aber eine zusätzliche Steuersprache erforderlich.

Dieser Ansatz vermindert einerseits die Flexibilität (aus der Sicht des Programmierers, der mit einer universellen Programmiersprache vorher alles hätte machen können) und erhöht sie andererseits (aus der Sicht des HTML-Codierers oder des Codierers von Aufträgen für Avanti, der schnell neue Zustände in die Suchmaschine integrieren kann oder vorhandene abwandelt). Dieses Sowohl-als auch gilt ebenso für die Komplexität: Die Zustände sind durch die Auslagerung in verschiedene Dateien einfacher identifizierbar und von ihrer Notation her „reiner“ (.htm-Dateien enthalten nur HTML, .job-Dateien enthalten Avanti-Befehle, .pl-Dateien enthalten (fast) kein Auftragselemente oder Layoutbeschreibungen), der Preis ist aber die zusätzliche Steuersprache, die beherrscht sein will.

Aufgrund der Anforderungen läßt sich schnell ableiten, welches die Grundfunktionalität der Steuersprache sein muß:

Die Kennzeichnung von Elementen der populo-Sprache erfolgt immer durch spezielle Zeichenfolgen, die mit 'PO' beginnen. Danach folgt ein je nach Bedeutung des Sprachelementes unterschiedliches Begrenzungszeichen, der zu interpretierende Teil, und als Abschluß noch einmal das Begrenzungszeichen.

Der einfachste Fall sind im normalen HTML-Text auftretende Variablen. Dabei ist nur der Variablenname anzugeben, was einfach durch die Zeichenfolge

PO!Variablenname!
geschieht.

Gelegentlich können dabei allerdings noch kleinere Modifikationen notwendig sein, z. B. eine Umwandlung einzelner Zeichen in HTML-Code. Für solche Zwecke stellt populo verschiedene Funktionen bereit. Die notwendige Kennzeichnung erfolgt fast genauso:

PO!Funktionenname( [Argument(e)] )!

Beispiel: Nehmen wir an, wir hätten verschiedene Variablen, die wie folgt belegt sind:

   Name = 'Paul'
Strasse = 'Pockelsstraße 5'
und außerdem in der .htm-Datei die Stelle
Person PO!Name! wohnt PO!Htm(Strasse)!.
populo macht dann daraus (Htm ist eine von populo bereitgestellte Umwandlungsfunktion):
Person Paul wohnt Pockelsstraße 5

Wenn man sich das obige Beispiel genauer ansieht, stellt sich natürlich die Frage, wie man Variable überhaupt mit Werten belegt. Allgemeiner gefragt: Wie bringt man populo dazu, zwischendurch gewisse Aufgaben auszuführen, ohne daß dies im Ergebnis zu sehen ist? Die Antwort darauf sind die populo-Routinen.

Die Syntax dafür ist

PO&Routinenname( [Argument(e)] )&
Routinen können ohne Argumente auftreten, aber auch hier sind runde Klammern notwendig. Jede dieser Aufrufe muß in einer eigenen Zeile stehen, da der Rest einer solchen Zeile ignoriert wird (dies kann als Möglichkeit für Kommentare ausgenutzt werden).

Beispiel: Um die im letzten Beispiel benutzte Variablenbelegung zu erhalten, kann u. a. der folgende Teil in der Template-Datei stehen:

PO&Set(Vorname, 'Paul')&
PO&Set(Name, 'Müller')&
PO&Set(Strasse, 'Pockelsstraße 5')&
PO&Set(Ort, 'Braunschweig')&

Unglücklicherweise gibt es einen ganzen Zoo von Zuweisungsoperationen, die hier nur kurz aufgelistet werden sollen:

Set
für die Zuweisung fester Zeichenketten an Variable
Assign
für die Zuweisung der Inhalte von Variablen an andere Variable
Append
für das Anhängen von Zeichenketten oder Inhalten von Variablen an eine Variable
IniVar
für die Initialisierung von Variablen aus HTTP-Feldern
Collect
für das Einsammeln paralleler HTTP-Felder
Poke
für das nachträgliche Einfügen von Werten in komplexe Strukturen
LinkIni
für einfaches Zusammenbauen von Links aus HTTP-Feldern

Es wurde schon erwähnt, daß noch eine konditionale Abarbeitung und eine Schleifenkonstruktion nötig ist. Diese fallen unter den Oberbegriff Kontrollstrukturen und beziehen sich in der Regel auf mehrere Zeilen, die in einer populo verständlichen Weise eingeschlossen werden müssen. Die Syntax sieht im Großen und Ganzen so aus:

PO?Kontrollstruktur [ ( [ Argument(e) ] ) ]?
Anweisungszeilen
[PO?…?]
Anweisungszeilen
PO?ENDKontrollstruktur [ …]?

In den Anweisungszeilen dürfen weitere Konstrollstrukturen eingeschachtelt sein.

Auch hier ein Beispiel zu Erläuterung: Es wurde nach Datensätzen mit einer bestimmten Bedingung gesucht, und das erhaltene Ergebnis soll jetzt angezeigt werden. Die Anzahl der gefundenen Datensätze sei dabei in der Variablen Anzahl festgehalten worden. Denkbar ist dafür die folgende Einleitung:

PO?IF( Anzahl > 1 )?
  Es wurden PO!Anzahl! Datensätze gefunden.
PO?ELSIF( Anzahl == 1 )?
  Es wurde ein Datensatz gefunden.
PO?ELSE?
  Es wurde kein Datensatz gefunden.
PO?ENDIF?

Unter den bisherigen Sprachelementen fehlt noch die Konstruktion, mit der auf Ergebnisse zurückgegriffen werden, die erst während der Abarbeitung des Auftrags durch Avanti festgelegt werden. Dazu wird die Möglichkeit ausgenutzt, daß mit Avanti eine beliebige Ausgabe mittels

write "" newline
erzeugt werden kann. Nun muß populo diese Zeile nur noch als für sich bestimmt erkennen können. Dies geschieht auf die übliche Weise, diesmal mit den Begrenzungszeichen ':':
PO:…:
Anstelle von steht nun üblicherweise der Aufruf einer Initialisierungsroutine. Die Konstruktion mit ':' sorgt dafür, daß die Initialisierung bis zum Zurücklesen des Resultats von Avanti verzögert wird. Dieser Zeitpunkt liegt immer noch vor der Ausgabe der Zeilen, d. h. auf das Ergebnis einer solchen Zuweisung, auch wenn sie am Ende des Rechercheergebnis erfolgt, kann schon in der ersten Zeile des Ausgabe-Templates zugegriffen werden.

Beispiel: Folgende Zeile könnte in einer .job-Datei vorkommen:

write "PO:Set(Txt, Int(" l ") Treffer zu 'PO!Begr!'):" n
Mit der Belegung „Blume“ für Begr wird die entsprechende Zeile in
write "PO:Set(Txt, Int(" l ") Treffer zu 'Blume'):" n
umgewandelt und als Bestandteil des Auftrags an Avanti übermittelt. Im Ergebnis des Auftrags tauch diese Zeile dann als einzelne Zeile der Form
PO:Set(Txt, Int( 0005 ) Treffer zu 'Blume'):
auf und beim Zurücklesen durch populo wird dann die Zuweisung von „5 Treffer zu 'Blume'“ an die Variable Txt durchgeführt.

Im Zusammenhang mit der speziellen, reservierten Variablen LineTyp ist diese Konstruktion unabdinglich:

Während des Zurücklesens des Resultats von Avanti wird jede Zeile entsprechend dem aktuellen Wert von LineTyp vorbehandelt. Liefert eine Anfrage mehrere Sorten Ausgabe, also etwa, weil unter der Kontrolle von Avanti entschieden wird, ob ein Registerausschnitt oder eine Kurztitelliste geliefert wird, so kann die Initialisierung von LineTyp nicht beim Absenden des Jobs erfolgen, sondern erst später:

Beispiel: Um populo mitzuteilen, daß Avanti als nächstes Registerzeilen liefert, muß in der .job-Datei an der entsprechenden Stelle die Zeile

…
find PER PO!Begriff!
if ok jump liste
// hier also Null Treffer, wir sparen uns einen leeren Schirm
// und bieten Browsing an:
write "PO:Set(LineTyp, 1):" newline  //Registerzeilen folgen
qrix PER PO!Begriff!
jump daswars

:liste write "PO:Set(LineTyp, 3):" newline //Kurztitelzeilen folgen list recnum

:daswars …

Für typische Arten von Avanti-Resultaten sind Vorverarbeitungen schon vordefiniert:


0
unspezifiziert, Fehlermeldungen

1
Registerauszüge
qrix f 1
(2)
erkannte Verweise in (1)
nur Ausgabe!
3
Kurztitellisten
list recnum
4
Vollausgabe
download
5
Satznummern intern speichern
list internal
11
Registerauszüge, noch Kurztitel holen
qrix f 1
(12)
erkannte Verweise in (12)
nur Ausgabe!
13
Satznummern für vollständige Kurzanzeige
list internal
14
Zwischenspeichern vollständiger Kurzanzeigen
list internal
(21)
geholte Kurztitelzeile zu 11
nur Ausgabe!
(22)
geholte Kurztitelzeile zu 12
nur Ausgabe!


Falls für eigene Zwecke (untergliederte Register etc.) stärkere Differenzierungen erforderlich sind, sind weitere LineTypen zu definieren, dazu muß aber typischerweise an mehreren Stellen in die datenbankspezifische Konfigurationsdatei eingegriffen werden.


komplexes Beispiel (Job): In Abhängigkeit von den Eingaben soll ein Registerauszug erstellt werden:

//PO&IniVar(Startwert,s1)&Startwert aus HTTP-Feld s1
//PO&IniVar(Endwert,s2)&Endwert aus HTTP-Feld s2
//PO&IniVar(Register,ix)&Register aus HTTP-Feld ix
qrix f 1
qrix m 99
// MaxShowRegister stammt aus der Konfigurationsdatei
qrix n PO!MaxShowRegister!
// Der Knopf 'rückwaerts blättern' habe im HTML-Formular für die
// Eingabe den Namen t_…_prev bekommen
//PO?IF( JobSubtyp eq "prev")?
  qrix -
//PO?ENDIF?
write "PO:Set(LineTyp,1):" newline   // WICHTIG!
//alternativ: Vorher Zeichenkette zusammenbasteln,
//braucht aber ebenfalls ein 'if'…
//PO?IF( Endwert )?
  qrix PO!Register! PO!Startwert! @ PO!Endwert!
//PO?ELSE
  qrix PO!Register! PO!Startwert!
//PO?ENDIF?


komplexes Beispiel (zugehörige Ausgabe):

<HTML>
<BODY>
<!-- "Link" wird vorinitialisiert: -->
<!-- PO&LinkIni(Link,db)&-->
<!-- %RegInfo aus der Konfigurationsdatei haben wir mit einem
  Feld Caption für den Klartext zum symbolischen
  Registernamen versehen -->
<!-- PO&Localize(RegInfo, Register, R_)&-->
<P>Gesucht wurde PO!Htm(Startwert) <BR>
  im Register PO!R_Caption!</P>

<PRE> <!-- PO?LOOP? -->

Weil LineTyp vor qrix auf 1 gesetzt war, haben wir jetzt Zugriff auf die Registerbestandteile als L_Count (Zählung), L_Recno (Satznummern) und L_0 (Registerinhalt). Wir formatieren die Zeilen als Links „in die Datenbank“ vom Anfragetyp showrec:
  (PO!L_Count!) <A HREF="PO!Link!&t_showrec=xyz&recs=PO!L_Recno!">
    PO!Htm(L_0)!</A>
<!-- PO?ENDLOOP? -->
</PRE>
Tsch&üuml;s!
</BODY>