|
Übersicht: Datenbanken
Allgemeines zur Datenbank Nutzung
Die Datenbank-Schnittstelle des xml2html-Paketes stellt die Verknüpfung zwischen xml-Daten und relationalen Datenbanken
auf eine einfache Art und Weise zur Verfügung.
Der Zugriff auf die relationale Datenbank wird mittels einiger einfacher xml-Tags realisiert,
mit denen wiederum xml-Code generiert wird.
Mit dieser Methode lassen sich einfache und komplexe Datenbankabfragen realisieren und sogar
Operationen zum Einfügen, Ändern und Löschen einzelner Datensätze sind so möglich.
Die aktuelle Datenbank-Schnittstelle basiert auf einer Version von Niclas Meier.
Die bisherige Schnittstelle
inkl. der Dokumentation steht natürlich weiterhin zur Verfügung.
xml2html unterscheidet 2 Arten von Datenbank Anfragen. Erstens die (nur lesenden) Abfragen von Tabellendaten und
zweitens das Verändern von Inhalten, also der schreibende Zugriff auf eine Tabelle.
Die Datenbank-Funktionalität wird über die beiden Anweisungen:
<tcl source="sql.so" type="LOAD">
<tcl source="database.tcl">
|
geladen.
Für den Zugriff auf die Datenbank sind einige weitere Informationen, wie der Name der Datenbank oder der Datenbank-User, notwendig.
Diese Informationen müssen xml2html durch Variablen zur Verfügung gestellt werden. Hierfür ist es notwendig, folgende
Variablendeklarationen sowie das Laden der Funktionalität in jede xml-Seite zu kopieren, die Datenbank Zugriff erhalten soll.
Natürlich können die Werte auch in einem Style-File deklariert werden, welches von den xml-Seiten eingebunden wird.
<set var="DBUSER" value="root">
<set var="DBNAME" value="xml2html">
<set var="DBHOST" value="localhost">
<set var="DBPASS" value="">
|
Sollen die folgenden Beispiele auf dieser Seite ausgeführt werden, muss es also eine Datenbank und einen User mit
den oben genannten Werten geben. Diese Beispiel-Konfiguration
- root-Benutzer ohne password - ist
nicht für den ernsthaften Gebrauch bestimmt. Sie müssen in diesem
Beispiel in der Datei man_db.style
modifiziert werden.
|
|
Verwendete Tabellen
Alle Beispiele beziehen sich dabei auf drei Beipieltabellen die mit diesem
Skript erzeugt werden können.
Der Inhalt der Tabellen:
Tabelle Person:
+------+-----------+------------+---------+
| p_id | p_vorname | p_nachname | p_alter |
+------+-----------+------------+---------+
| 1 | gustav | krause | 34 |
| 2 | egon | hahn | 45 |
| 3 | karl | lehmann | 35 |
| 4 | juergen | hartmann | 65 |
| 5 | richard | maier | 33 |
| 6 | karl | krause | 50 |
+------+-----------+------------+---------+
Tabelle Kind:
+------+-----------+------------+---------+----------+
| k_id | k_vorname | k_nachname | k_alter | k_ort |
+------+-----------+------------+---------+----------+
| 1 | franz | maier | 35 | hamburg |
| 2 | petra | lehmann | 5 | berlin |
| 3 | thomas | hahn | 12 | muenchen |
| 4 | britta | lehmann | 16 | berlin |
| 5 | andreas | krause | 45 | muenchen |
+------+-----------+------------+---------+----------+
Tabelle Adresse:
+------+------+---------------+--------+----------+
| a_id | p_id | strasse | hausnr | ort |
+------+------+---------------+--------+----------+
| 1 | 1 | hauptstrasse | 2 | wedel |
| 2 | 2 | nebenweg | 23 | hamburg |
| 3 | 3 | marienstrasse | 124 | muenchen |
| 4 | 5 | nordtor | 11 | muenchen |
+------+------+---------------+--------+----------+
|
Die Makros für die Ausgabeformatierungen sind in der Datei man_db.style definiert.
|
|
Datenbank-Abfragen
Für das Abfragen von Daten ist der <sql-query>-Tag zuständig.
Der Tag darf daher nur eine select-Anfrage enthalten, ein insert oder
delete ist mit diesem Tag nicht möglich.
<sql-query stmt="select p_vorname, p_nachname from person order by p_nachname;"
ressection="s_person_name" resentry="r_person_name" resempty="person_leer" reserror="person_error">
</sql-query>
|
Der Parameter stmt enthält die auszuführende Anfrage, die weiteren Parameter dienen der Formatierung des Ergebnisses.
ressection stellt dabei das äussere Gerüst der Darstellung da, mit resentry werden die
einzelnen Ergebniszeilen der Anfrage formatiert.
<define name="S_PERSON_NAME"
effrows=""
body='$EFFROWS Zeilen gefunden<br><table>'
end='</table>'
>
<define name="R_PERSON_NAME"
p_vorname=""
p_nachname=""
body='<tr><td>$P_VORNAME</td><td>$P_NACHNAME</td></tr>'
>
|
ressection enthält in diesem Beispiel nur eine einfache Tabelle und zusätzlich die Information wieviele Zeilen
($EFFROWS) die Ergebnismenge enthält.
Mit resentry können die einzelnen Ergebniszeilen der Anfrage formatiert werden.
Auf die einzelnen Spalten kann dabei über die angegebenen Namen in der sql-Anfrage zugegriffen werden.
resempty und reserror
dienen der Darstellung einer leeren Ergebnismenge bzw. eines Fehlers.
Wird einer der Parameter nicht angegeben, geht xml2html davon aus,
dass ein Makro mit dem entsprechenden Parameternamen existiert.
Die Verarbeitung erfolgt hierbei also analog zum toc-Tag.
Die oben genannte Anfrage würde, vorausgesetzt die Datenbank ist
installiert und der Datenbankserver läuft, somit folgendes Ergebnis liefern:
|
|
Leere Ergebnismengen und fehlerhafte Anfragen
Die folgenden Beispiele demonstrieren die Arbeitsweise des
Datebankzugriffs nur dann korrekt, wenn die Datenbank überhaupt
zugreifbar
ist. Ist dieses nicht der Fall, so erscheint immer die gleiche Fehlermeldung.
Von diesen Seiten gibt es eine statische Version, in dieser
kann man die Wirkungsweise der Anfragen erkennen, auch wenn die
Datenbank nicht installiert ist.
Eine Anfrage
<sql-query stmt="select p_nachname from person where p_alter = 10;" resempty="person_leer"></sql-query>
|
die keine Ergebniszeilen liefert, würde das in resempty angegebene Makro ausführen,
in diesem Fall: person_leer
Database not open invalid command name "sql"
Eine fehlerhafte Anfrage
<sql-query stmt="select p_nachname from personen where p_alter = 10;" resempty="person_leer"></sql-query>
|
würde diese Ergebnis liefern:
Database not open invalid command name "sql"
Bei der Definition des "Fehlermakros" kann auf zwei Parameter zugegriffen werden,
usermsg und systemmsg. usermsg stellt dabei
eine vom Entwickler der Schnittstellen definierte Fehlermeldung da, systemmsg wird vom
Datenbank System generiert.
<define name="RESERROR"
usermsg=""
systemmsg=""
body='<red>$USERMSG<br>$SYSTEMMSG</red>'
>
|
|
|
* Anfragen
Natürlich sind auch "select * from .." Anfragen möglich. Der Zugriff auf die einzelnen Spaltenwerte erfolgt
hierbei ebenfalls über den Spaltennamen in der Tabelle.
<sql-query
stmt="select * from kind where k_alter > 10 order by k_alter;"
resentry="r_kind_all"
ressection="s_kind_all"></sql-query>
|
Database not open invalid command name "sql"
|
|
Unterabfragen
Einige Datenbanken, wie z.B. MySQL
lassen leider keine Unterabfragen zu.
xml2html ist allerdings in der Lage diesen Nachteil zu beheben und stellt dafür
den <sql-subquery>-Tag zur Verfügung.
<sql-query
stmt="select * from person where p_alter > all <subquery> order by p_nachname;"
resentry="r_person_all"
ressection="s_person_all"
resempty="person_leer"
>
<sql-subquery stmt="select k_alter from kind;"></sql-subquery>
</sql-query>
|
Um eine Unterabfrage ausführen zu können sind zwei Schritte notwendig.
- Definieren einer Anfrage in einem <sql-query>-Tag.
Die Anfrage muss dabei an der Stelle an der
sich normalerweise die Unterabfrage befindet,
dass Schlüsselwort <subquery> enthalten.
- Definieren einer <sql-subquery>
Anfrage die in den <sql-query>-Tag geschachtelt
sei muss.
Das Ergebnis der Anfrage wäre dann:
Database not open invalid command name "sql"
Unterabfragen lassen sich natürlich auch wiederum beliebig tief schachteln.
Es ist also eine Anfrage die eine Unterabfrage enthält, die eine
Unterabfrage enthält, ... möglich.
<sql-query
stmt="select * from person where p_alter in <subquery> order by p_nachname;"
resentry="r_person_all"
ressection="s_person_all"
resempty="person_leer"
>
<sql-subquery
stmt="select k_alter from kind where k_ort in <subquery>;">
<sql-subquery
stmt="select ort from adresse;"></sql-subquery>
</sql-subquery>
</sql-query>
|
Das Ergebnis der Anfrage wäre dann:
Database not open invalid command name "sql"
Lässt die Datenbank Unterabfragen zu, ist der Umweg über den <sql-subquery>-Tag natürlich nicht
nötig. Bei diesen Datenbanken kann die Unterabfrage direkt im <sql-query>-Statement angegeben werden.
|
|
Vereinfachen der Makrodefinition
Da bei der Definition eines "Zeilenmakros" die Spaltennamen der Tabelle angegeben werden müssen, kann es sehr schnell zu
Codeverdopplung kommen, wenn die Ergebnisse zweier unterschiedlicher Tabellen gleich dargestellt werden sollen.
<define name="KIND_ZEILE"
k_vorname=""
k_nachname=""
body='<tr><td><b><italic>$K_VORNAME</italic></b></td><td><b><italic>$K_NACHNAME</italic></b></td></tr>'
>
<define name="PERSON_ZEILE"
p_vorname=""
p_nachname=""
body='<tr><td><b><italic>$P_VORNAME</italic></b></td><td><b><italic>$P_NACHNAME</italic></b></td></tr>'
>
|
Die beiden Makros unterscheiden sich nur in den Namen der Tabellenspalten.
Durch die Definition einer Zwischenstufe kann diese Verdopplung allerdings vermieden werden. Hierbei wird ein
komplexes "Standardmakro" definiert (im Beispiel: STANDARD_ZEILE) in dem die Spaltennamen der Tabelle nicht mehr
vorkommen. Jetzt muss nur noch für jede Tabelle/Abfrage ein einfaches Makro geschrieben werden, welches die Umbennenung
der Spaltennamen in die Standardnamen übernimmt und das komplexe Makro aufruft.
<define name="KIND_ZEILE"
k_vorname=""
k_nachname=""
body='<standard_zeile v1="$K_VORNAME" v2="$K_NACHNAME">'
>
<define name="PERSON_ZEILE"
p_vorname=""
p_nachname=""
body='<standard_zeile v1="$P_VORNAME" v2="$P_NACHNAME">'
>
<define name="STANDARD_ZEILE"
v1=""
v2=""
body='<tr><td><b><italic>$V1</italic></b></td><td><b><italic>$V2</italic></b></td></tr>'
>
|
|
|
Datenbank-Änderungen
Für das Verändern von Tabelleninhalten wird der <sql-write>-Tag verwendet.
Mit ihm lassen sich Datensätze hinzufügen, löschen und ändern.
<sql-write stmt="insert into kind values (0,'anja','mueller',4,'hamburg');" reswrite="resinsert"></sql-write>
<sql-write stmt="delete from kind where k_vorname= 'anja';"></sql-write>
<sql-write stmt="update kind set k_vorname='schulze' where k_vorname='lehmann';" reswrite="resupdate"></sql-write>
|
Der <sql-write>-Tag hat die Parameter stmt
sowie reswrite und
reserror. Das Makro reswrite wird ausgeführt,
wenn die Änderung erfolgreich war,
reserror im Fehlerfalle.
Die Angabe dieser beiden Parameter kann wie im
<sql-query>-Tag
weggelassen werden, dann wird durch xml2html
nach einem Makro mit dem Namen reswrite bzw.
reserror gesucht.
Ausgaben der oberen Änderungsanfragen wären:
insert: Database not open invalid command name "sql"
delete: Database not open invalid command name "sql"
update: Database not open invalid command name "sql"
|
|
|