Grundsätzlich unterscheidet DSSSL sich
von CSS dadurch, dass
erstere eine richtige
Programmiersprache enthält. Mit ihr
lassen sich außer Angaben über Schriftgröße und -typ auch
Berechnungen vornehmen. Das klingt zwar gut, aber leider ist
die Sprache recht kompliziert, so dass man sie Web-Autoren kaum
zumuten kann. Wer sich als
HTML-Kenner daran gewöhnen muss, mit
neuen Sprachen (= DTDs) zu arbeiten oder gar
die Strukturbeschreibung selbst erst zu entwerfen, der will
sich möglicherweise nicht auch noch mit
Lisp belasten.
Innerhalb der Stilsprache existieren zwei Teilbereiche, die entwickelt beziehungsweise spezifiziert worden sind, weil der gesamte Umfang anscheinend zu groß war, als dass mit seiner vollständigen Implementierung zu rechnen gewesen wäre. Die Core Query Language und die Core Expression Language stellen dar, was in einer DSSSL-Implementierung zwingend ist.
DSSSL-Implementierungen gibt es auch
frei verfügbar. Hier dürfte James Clarks Jade unter anderem deshalb am
verbreitetsten sein, weil diese
DSSSL-Maschine
für mehrere
Betriebssysteme (Unix-Derivate inklusive Linux plus Win32)
vorhanden ist — außerdem ist sie
kostenlos erhältlich. Jade beinhaltet zwar nicht
alles, was die DSSSL-Spezifikation bietet, aber
es ist ein hervorragendes Tool, um etwa XML-
oder SGML-Dokumente in HTML zu
wandeln. Ein Beispiel weiter unten wird dies
zeigen.
Für eine beliebige DTD muss der zuständige Stylesheet-Schreiber abhängig vom gewünschten Ergebnis festlegen, welche Elemente wie darzustellen sind — oder ob sie übergangen werden. Letzteres erreicht man durch:
(element wasauchimmer (empty-sosofo))
In CSS hieße dieser Ausdruck:
wasauchimmer { display: none }
Hinter einem SOSOFO steckt eine
Specification of a Sequence of a Flow
ObjectObwohl
Spezifikation
weiblich ist, verwenden wir hier den männliche Artikel für
das Akronym. Im Grunde entspricht dies nur dem Sprachgefühl
der Autoren (der Duden kennt das Wort nicht), aber die
Wortendung und das schließende Object
fördern diesen
Sprachgebrauch.. Obiges Beispiel ist ein
Sonderfall, nämlich das leere SOSOFO. Die oben
gezeigte Elementfunktion sieht formaler so aus:
(element elementname SOSOFO)
Ein DSSSL-Stylesheet heißt eigentlich
Spezifikation
, vor allem deshalb, weil es mehr als nur
Stilvorgaben enthalten kann, wie sich in wenigen
MinutenVorausgesetzt, Sie lesen in diesem Kapitel
konsequent weiter, anstatt gerade Kaffee holen zu wollen, weil
die vielen Klammern, die dieses Kapitel noch enthalten wird,
Sie schrecken. Keine Sorge, sie (die Klammern) werden alle
wieder geschlossen ... deutlicher zeigen wird.
Deutlicher
, weil schon das obige Beispiel (Ausgabe der
Elementposition) mehr ist als eine reine Stilvorgabe. Vordefinierte
DSSSL-Funktionen gibt es zu viele, als dass wir
sie hier alle auflisten könnten.
Prinzipiell lassen sich alle DSSSL-Funktionen innerhalb eines Stylesheets nutzen. Darüber hinaus kann man eigene Funktionen programmieren, die dann Bestandteil des Stylesheets sind. Das folgende Beispiel zeigt zwei Jade fehlende Funktionen, die so wörtlich der DSSSL-Spezifikation entnommen sind. Mit ihrer Hilfe lässt sich die Ausgabe der Position eines Elements realisieren. Sie aus dem Standard-Dokument zu übernehmen, resultierte aus der Arbeit mit Jade respektive der Tatsache, dass James Clark eben nicht alles aus dem DSSSL-Standard implementiert hat. Die DSSSL-Spezifikation enthält noch mehr an Beispielen.
; ----- node-list-length + node-list-reduce (define (node-list-reduce nl combine init) (if (node-list-empty? nl) init (node-list-reduce (node-list-rest nl) combine (combine init (node-list-first nl))))) (define (node-list-length nl) (node-list-reduce nl (lambda (result snl) (+ result 1)) 0))
Die Einzelheiten der Scheme-Programmierung können wir hier leider nicht erläutern; ein paar Anmerkungen zu den Funktionen müssen genügen: node-list-reduce erhält als Parameter eine Node List (Knoten in der internen Dokumentrepräsentation), einen Funktionsnamen und einen initialen Wert. Falls die Knotenliste leer ist, wird der Anfangswert ausgegeben. Ansonsten ruft node-list-reduce sich rekursiv auf, und zwar mit der durch node-list-rest um den ersten Node verkürzten Liste, dem Funktionsnamen sowie einem Aufruf dieser Funktion. node-list-length ruft node-list-rest mit der Node-List, einer Lambda-Funktion sowie dem Anfangswert auf. Ausgegeben wird schließlich der Wert, den init in node-list-reduce zum Schluss hat.
Zum Trost für alle, denen die DSSSL-Spezifikation selbst zu weit geht: Die hier versammelten Beispiele sind für ein solches Kapitel kompliziert genug. Ein weiteres (15) wird zwei vollständige Style Sheets für eine kleine Anwendung vorstellen, die auch online auszuprobieren sind.
Eigene Funktionen in DSSSL-Style-Sheets zu verwenden erfordert deren Formulierung und Aufruf an der richtigen Stelle. Enthält etwa ein Element monat in einem XML-Dokument jeweils die Ziffer des betreffenden Monats ("10" statt des Strings "Oktober"), kann eine kleine Funktion die Ausgabe des Strings bewirken.
(define (getmonth mo li lang) (if (= mo 1) (if (equal? lang "de") (car (car li)) (car (cdr li))) (getmonth (- mo 1) (cdr li) lang))) (define monate (list (list "Januar" "January") (list "Februar" "February") (list "März" "March") (list "April" "April") (list "Mai" "May") (list "Juni" "June") (list "Juli" "July") (list "August" "August") (list "September" "September") (list "Oktober" "October") (list "November" "November") (list "Dezember" "December"))) ; ----- Aufruf im Element mit: (literal (getmonth (string->number (data (current-node))) monate "de"))
Die Funktion getmonth erledigt diese Aufgabe, indem
sie fragt
, ob der übergebene Monat "1" ist. Falls ja,
fragt die Funktion nach der ebenfalls als Parameter
übergebenen Sprache (hier "de") und gibt entweder den
deutschen oder, in diesem Beispiel die letzte Zeile, den
englischen Monatsnamen aus. Dazu ist eine Liste
erforderlich, die die Begriffe enthält; hier ist es die
Liste monate, die für jeden Monat wiederum eine
Liste mit den Namen in verschiedenen (hier nur zwei)
Sprachen vorhält.
Falls der Monat nicht der Januar ist
(= mo 1), kommt ein für Lisp
typisches Programmkonstrukt zum Einsatz: die
Rekursion. getmonth ruft sich selbst wieder
auf, allerdings mit der um alle Januar-Einträge
verringerten (getmonth (- mo 1) (cdr li) lang)
Liste und dem um 1 kleineren Parameter des
Monats. Irgendwann
(insgesamt sind maximal zwölf
Durchläufe möglich) ist der Wert von mo 1 und aus der
dann in der Gesamtliste vorn stehenden Liste kann
der richtige Monat ausgegeben werden.
Was hier trivial erscheint, kann wichtig werden, wenn in einer größeren Anwendung vier oder fünf Sprachen gleichzeitig zu unterstützen sind. Denn solche Funktionen lassen sich unschwer erweitern.