Praktisch jede moderne Webpräsenz basiert auf Server-seitiger Programmlogik inklusive Datenbank. Doch HTML-Seiten auf CD-ROMs müssen darauf verzichten. Fehlende Rechenkapazität auf dem Server ist ein weiteres Argument, um Programmlogik auf die Client-Seite zu verlegen.
Zwar lassen sich dynamische Elemente in Javascript leicht programmieren, aber wer mit größeren Datenmengen jongliert, vermisst schmerzlich die Datenbank. Hier springt die in Javascript programmierte Datenbank Public SQL [1] in die Bresche. Zwar kann sie aufgrund des Sicherheitsmodells von Javascript keine neuen Daten speichern, denn der Browser darf nicht per Javascript auf die Festplatte des Rechners schreiben. Doch vorgegebene Daten erschließt sie mit jedem Webentwickler geläufigen SQL-Befehlen (siehe Kasten "Installation und Anwendung").
|
Die Installation von Public SQL, das sein Autor Jörg Siebrands unter die MIT-License gestellt hat, ist ganz einfach: Der Download der einzelnen Datei »publicsql.js« von der Downloadseite reicht aus. Von der Version 1.1 gibt es auch ein Zip-Archiv mit Dokumentation, Beispielen und einer unkomprimierten Javascript-Datei der Bibliothek mit Kommentaren. Wer Public SQL in seine Website einbinden möchte, fügt in den Kopf seiner HTML-Seite die Zeile
<script type="text/javascript"
src="publicsql.js"></script>
ein und legt die heruntergeladene Javascript-Datei im selben Verzeichnis ab. Alternativ lässt sich auch direkt »http://www.publicsql.org/publicsql.js« als Quelle angeben. Dann benutzt die Anwendung immer die neuste Version, riskiert jedoch, dass sich der Pfad irgendwann einmal ändert oder zum Zeitpunkt des Einsatzes gerade keine Netzverbindung besteht. Abfragen durch Javascript-Event auslösen
Um Abfragen zu erledigen, fügen Entwickler im Body der Webseite beispielsweise eine Funktion »abfrage()« in einen »<script>«-Container vom Typ Javascript ein, die sie durch ein Ereignis auslösen. In Frage kommen etwa »<body onload="abfrage()">« beim Laden des Dokuments oder »<button onclick="abfrage()">Drück mich</button>« durch Knopfdruck. Der zentrale Aufruf, um eine SQL-Abfrage innerhalb von »abfrage()« in Auftrag zu geben, lautet:
publicSQL.query("select * from projekte",
"publicSQL.show");
Dabei erlaubt die Bibliothek einen vereinfachten SQL-Dialekt für die Abfrage (siehe Tabelle 1). Die einzelnen Relationen, hier »projekte«, erwartet sie pro Tabelle in separaten Dateien mit der Endung ».ptf«, die im gleichen Verzeichnis wie die HTML-Seite und Javascript-Bibliothek liegen. Jede Datei folgt diesem Schema:
/* Portable Table Format 0.9 */
porTables[porTables.length] = new Array(
"land", "summe", "aktivität",
"Deutschland", 100000, "Tunnelbau",
"Belgien", 23456, "Förderprojekt",
[...]
"Frankreich", 76543, "Infrastruktur",
3);
Die ersten beiden Zeilen schreiben das Format vor, die dritte enthält Überschriften der Attribute. Alle weiteren Zeilen enthalten die Datentupel, getrennt durch Kommata. Als letzte Zeile folgt die Anzahl der Attribute pro Zeile. Damit lassen sich besonders Json- oder CSV-Dateien leicht in das Format überführen. Da eine PTF-Datei technisch aus gültigem Javascript besteht, müssen nicht notwendigerweise alle Werte eines Tupels in einer Zeile stehen. Allerdings erfordern einige Zusatzwerkzeuge außerhalb von Public SQL diese Bedingung.
Callback-Funktion statt Rückgabewert
Die Funktion »PublicSQL.query()« gibt selbst keinen Wert zurück. Stattdessen ruft sie asynchron die Funktion auf, die sie als zweiten Parameter übergeben bekommt. Die Bibliothek liefert eine Funktion »PublicSQL.show()« mit, die mit diesem Interface umgehen kann und aus dem Ergebnis eine einfach formatierte HTML-Tabelle baut. Bei komplexeren Anfragen und deren Ergebnisdarstellung schreiben Entwickler besser eine eigene Funktion, die als Parameter ein zweidimensionales Javascript-Array erwartet und es in HTML umsetzt.
Weitere Funktionen und Attribute dienen dazu, die Pfade zu den Tabellen zu definieren, sie vorab zu laden, die Sortierung zu bestimmen oder zur Fehlerbehandlung. Die Webseite enthält eine vollständige Liste der Funktionen und führt die meisten in Beispielen vor [3].
|
Public SQL unterstützt »SELECT«-Statements mit »WHERE«- und »ORDER BY«-Klauseln (Tabelle 1). Außer String- und Zahlenfeldern dürfen Tabellen auch Datumspalten enthalten. Mehrere Tabellen sind per Inner Join verknüpfbar und es gibt eine »DISTINCT«-Anweisung.
|
|
|
Schlüsselwort
|
Bedeutung
|
|
SELECT
|
Suche in der Datenbank. Genaugenommen der einzige SQL-Befehl, den Public SQL kennt.
|
|
DISTINCT
|
Filtert mehrfache Vorkommen in der Ergebnisliste aus.
|
|
FROM
|
Es sind Joins von mehreren Tabellen möglich. Für jede Tabelle muss eine PTF-Datei gleichen Namens vorliegen.
|
|
AS
|
Vergibt neue Namen für das ausgewählt Attribut.
|
|
WHERE
|
Die Suchbedingung kennt die Junktoren AND, OR und NOT, Klammern sowie Vergleichoperatoren.
|
|
ORDER BY
|
Sortiert nach einem oder mehreren der Ergebnisattribute.
|
|
ASC
|
Sortiert aufsteigend.
|
|
DESC
|
Sortiert absteigend.
|
Der Leistungsumfang ist überschaubar, dennoch schrumpfen viele in reinem Javascript schwer lösbare Aufgaben mit Public SQL auf wenige Zeilen Code zusammen. Eine Beispielanwendung, die in beliebigen Feldern einer Datenbank mit Obst- und Gemüsesorten sucht (siehe Abbildung 1), demonstriert dies. Abbildung 2 zeigt schematisch ihren Aufbau. Die ganze Anwendung lässt sich vom FTP-Server des Linux-Magazins herunterladen [2] und natürlich auch offline ausprobieren.
Abbildung 2: Alle Macht den Eventhandlern: Erst nach einem Klick erscheinen das Dropdown »Feldauswahl« und das Eingabefeld für den Suchtext in der Seite.
Pro Tabelle benötigt Public SQL eine für Javascript erreichbare Datei: Die liegt entweder - etwa bei einer Daten-CD - im lokalen Dateisystem oder lässt sich per HTTP-Protokoll nachladen. Jede besteht aus einem Array, das sich in der Praxis leicht aus CSV-Dateien erzeugen lässt. Lediglich zwei Zeilen am Beginn und eine am Ende sind hinzuzufügen. Näheres erläutert die Dokumentation [3].
Einbahnstraße
Gibt es keinen Server, der auf per »POST« oder »GET« zugeschickte Werte mit einer neuen Seite antwortet, übernimmt eine durchgehend geöffnete Seite neben der Funktion als Suchformular auch die Ergebnisanzeige. Das knappe Gerüst für beides findet sich im HTML-Code aus Listing 1. Die Zeilen 7 bis 11 definieren ein Formular, das nur zwei Buttons enthält: Der Button »+ Suchkriterium« (Zeile 8) fügt über den verknüpften Eventhandler »add_searchfield()« eine Zeile mit einer Suchbedingung ein (Abbildung 1). Per Klick auf »Suche ausführen« (Zeile 10) geht\'s los. Unter dem Formular steht im Code ein leeres »div«-Tag (Zeile 13), in das die Funktion »execute_search()« das Suchergebnis schreibt.
01 <head>
02 <meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
03 <script type="text/javascript"
src="publicsql.js"></script>
04 </head>
05 <body>
06 Suche nach:
07 <form name="form" action="">
08 <button onclick="add_searchfield();
return false">
+ Suchkriterium</button>
09 <div id="inputarea"></div>
10 <button onclick="execute_search();
return false">
Suche ausführen</button>
11 </form>
12 Suchergebnis:
13 <div id="result"></div>
14 </body>
|
Um eine Suche zu initiieren, klickt der Anwender zunächst auf »+ Suchkriterium«. Damit fügt er ein Listenfeld ein, indem er das Feld wählt, in dem er suchen möchte (Abbildung 1, linke Spalte). Fürs Einfügen zuständig ist der Eventhandler »add_searchfield()« (Listing 2). Die erste Zeile der Funktion füllt »code« daher mit dem öffnenden Tag eines Dropdown-Listenfelds: »<select name="searchindex" onclick="add_input(Index, this)">«. Den dort enthaltenen Onklick-Eventhandler erläutert der nächste Abschnitt. Eine Schleife (Zeilen 10 bis 14) fügt für jedes Element des Array »fieldnames« ein »option«-Tag hinzu:
<option value="0">[bitte wählen]</option> <option value="1">Obst oder Gemüse</option>
und so weiter. Zeile 15 schließt das »select«-Tag und fügt außerdem noch eine leeres »span«-Tag mit der ID »input_search Zeilenindex« hinzu. Dies erleichtert »add_input()« später das Einfügen des Eingabefelds in der zweiten Spalte. Der Zeilenzähler »fieldcount« ermöglicht es, die Divs auseinanderzuhalten.
01 var fieldcount=0;
02 var fieldnames=[ "[bitte wählen]",
03 "Obst oder Gemüse", "Farbe",
04 "Geschmack", "Größe" ];
05
06 function add_searchfield() {
07 var code = 'n<select name="search' +
08 fieldcount + '" onclick="add_input(' +
09 fieldcount + ', this)">' + 'n';
10 for (i in fieldnames) {
11 code += '<option value="' + i +
12 '">' + fieldnames[i] +
13 '</option>n';
14 }
15 code += '</select>n<span id="input_search' +
16 fieldcount + '"></span>';
17 fieldcount++;
18 var newSpan=document.createElement('div');
19 newSpan.innerHTML=code;
20 document.getElementById("inputarea").
21 appendChild(newSpan);
22 }
|
Zweite Wahl
Der Benutzer wählt im Dropdown-Feld aus einer im Code definierten Liste von Suchfeldern (Abbildung 1). Wegen des »value«-Tag erhält das in Zeile 11 erzeugte Feld einen numerischen Wert von 0 bis 4. Ein Mausklick auf das Dropdown-Feld ruft den »onclick«-Handler mit dem Zeilenzahl-Zähler »fieldcount« sowie einer Referenz auf das ihn aufrufende Dropdown-Feld (»this«) auf - bis jetzt jedoch nur theoretisch, denn erst die Zeilen 18 bis 21 fügen den HTML-Code tatsächlich in die Seite ein.
Abbildung 1: Public SQL implementiert eine lokale Suche über beliebig viele Felder einer Datenbank, indem Javascript ein dynamisches SQL-Statement erzeugt.