Die Website Meta Language
von Michael Kleinhenz (michael.kleinhenz@unix-ag.org)

Die WML ist ein freies HTML-Toolkit, das aus neun unabhängigen Programmen besteht. Diese Präprozessoren ermöglichen weitergehende High-Level-Funktionen, wie z.B. das Verwenden von Perl oder das Implementieren eigener "HTML"-Tags. Die META Language erleichtert so das Erstellen und Warten von großen Websites.

Inhalt

WML - Der Traum aller Webmaster?
Grundlegende Konzepte
    Sequentielles Filtern
    Makrokonstrukte
    Programmierkonstrukte
    Codemischung und Fixup
    Die Slicetechnik
Ein Beispiel

WML - Der Traum aller Webmaster?

Ein typisches Szenario für viele Webmaster, die größere Websites verwalten: Nach der Fertigstellung des neuen Seitenlayouts wird festgestellt, dass ein weiterer Menüeintrag in der Navigationsleiste fehlt. Nun sitzt man in der Tinte: 42 Webseiten, in denen ein Button eingebaut werden muss. Welche Möglichkeiten gibt es in einem solchen Fall? Natürlich können mit einem sed-Skript alle Seiten automatisiert geändern werden, doch dies ist nicht jedermanns Sache, und die Komplexität der Skripte wächst mit den Fähigkeiten so stark an, dass man schnell den Überblick verliert. Zudem sind größere Änderungen am grundlegenden Design der Site auf diese Weise nur schwer möglich.

Eine weitere Lösung ist die Verwendung von großen Web-Authoring-Systemen wie z.B. Fusion, doch diese sind entweder für Linux (noch) nicht verfügbar, sehr teuer oder zu unflexibel gegenüber der hier vorgestellten Lösung: Die Website Meta Language.

WML ist ein Satz von GPL-Programmen von Ralf S. Engelschall, mit denen es möglich ist, aus in einer Meta-Sprache geschriebenen Quelldateien HTML-Seiten zu erzeugen. Natürlich ist WML nicht so einfach zu bedienen wie übliche grafische Authoring-Tools, doch diesen Makel macht es durch enorme Funktionalität und Mächtigkeit wieder wett. Aber auch Anfänger brauchen keine Angst zu haben, sich WML einmal anzuschauen. Wer sich etwas mit der Linux-Kommandozeile auskennt und HTML beherrscht, wird auf keine größeren Probleme stoßen.

Grundlegende Konzepte

Was sind nun die grundlegenden Strukturen von WML? Die Dokumentation nennt hier drei große Konzepte, die ich hier in etwas abgewandelter Darstellung vorstellen möchte.

WML ist eigentlich ein Präprozessor, der in neun unabhängigen Durchläufen aus einer Eingabedatei eine HTML-Ausgabe erzeugt.

Sequentielles Filtern

WML geht dabei sequentiell vor. Es wendet die Durchgänge 1 bis 9 nacheinander auf die Eingabedatei an und erzeugt damit schrittweise eine verfeinerte Version der Ausgabe. Natürlich kann man von der Kommandozeile aus auch spezifizieren, welche der Präprozessoren angewendet werden sollen, doch dies dürfte im normalen Betrieb nicht notwendig sein.

Im ersten Schritt werden Anweisungen in der Form

#include <includefile>

aufgelöst. Die Bedeutung ist äquivalent zur entsprechenden C/C++-Notation: die Datei includefile wird im Standard-Suchpfad von WML gesucht und syntaktisch an die Stelle der Anweisung eingefügt. Ähnlich wie bei Perl werden in dieser Phase auch folgende Anweisungen bearbeitet:

#use wml::category::file

die bedeutungsäquivalent zu

#include <catgeory/file.wml>

sind, also im Standard-Include-Verzeichnis von WML liegende Module in den Sourcecode einfügen. Diese Standard-Module teilen sich in sechs Kategorien auf:

Standard (std)
Basis-Funktionalität des WML-Systems, wie z.B. erweiterte HREFs oder automatische Inhaltsverzeichnisse.
Webdesign (des)
Funktionen für Design und Gestaltung. Orginalkommentar der WML-Manpage: "These are tagsets which help webdesigners of the 3rd generation fighting against the puristic plain HTML."
Formatting (fmt)
Erweiterte Formatierungsfunktionen für Tabellen, Verbatim-Text und anderes.
Import (imp)
Tags zum Importieren externer Daten und deren Umwandlung nach HTML.
Support (sup)
Zusätzliche Tags, die weitestgehend nur von anderen Modulen verwendet werden. Mit diesen Befehlen kann man beispielsweise serverseitige Imagemaps in Client-Imagemaps umwandeln.
System (sys)
WML-System-Tags. Enthält den Startup-Code für das WML-System.

Makrokonstrukte

Eines der Stärken der WML ist die Möglichkeit, eigene Tags zu definieren. Die Tags haben ähnliche Funktionalität wie herkömmliche HTML-Befehle. Ein eigener Befehl könnte so aussehen:

<ltlogo>

Dieser Tag fügt z.B. dann das LinuxTag-Logo ein. Den Befehlen können optional auch Parameter übergeben werden:

<ltlogo type=1>

Eine spezielle Form dieser Funktion stellt der sogenannte "Container" dar:

<ltfont>
Hier kommt ein Text.
</ltfont>

Wie bei einem HTML-Container wird ein Befehl auf einen Textbereich angewendet, der von einem öffnenden und einem schließenden Tag eingegrenzt wird. Die Definition eines Tags bleibt dabei denkbar einfach:

<define-tag foo>
HTML-Code
</define-tag>

<define-container bar>
Code
%body
Weiterer Code
</define-container>

In einer Containerdefinition wird durch %body der in den Tag eingeschlossene Text repräsentiert. Ein einfaches Beispiel:

<define-tag email>
<a href="mailto:michael.kleinhenz@unix-ag.org">michael.kleinhenz@unix-ag.org</A>
</define-tag>

Meine E-Mail-Adresse ist <email>.

Programmierkonstrukte

Ein weiteres mächtiges Feature in WML ist die Möglichkeit Perl- oder m4-Konstrukte direkt in WML-Quelldateien zu verwenden. Im ensprechenden Durchlauf wird der Perl-Code aus dem Dokument herausgelöst, ausgeführt und die Ausgabe wieder in das Dokument eingefügt. Ein einfaches Beispiel:

<:
   for ($i=1;$i<=10;$i++)
        {
                print $i."\n";
        }
:>

Wie man sieht, müssen die Perl-Anweisungen in das Raster <: Code :> gebracht werden. Alternativ kann auch <:= Code :> für die direkte Ausgabe des Ergebnisses verwendet werden, d.h. das Konstrukt wird zu <: print Code :> ausgewertet. Natürlich kann man auf die gesamte Perl-Funktionalität zurückgreifen und so zum Beispiel Verzeichnisse auslesen. In der Unix-AG wird eine solche Methode zum Beispiel verwendet, um dynamisch ein Inhaltsverzeichnis aller verabschiedeter Sitzungsprotokolle zu generieren.

Codemischung und Fixup

Als Nächstes wird der generierte Code gemischt und fixiert. Unter "Mischen" versteht WML allerdings eine unscheinbare, aber äußerst mächtige Funktionalität: Ein Einfügepunkt wird mit

<<NAME>>

markiert. Später kann diese Stelle mit

..NAME>>
  Hier kommt der Text
<<..

referenziert und der markierte Codeblock an die markierte Stelle eingefügt werden. Ein Beispiel für eine einfache Tabelle könnte folgendermaßen aussehen:

<table>
<tr>
<td><<LINKS>></td>
<td><<MITTE>></td>
<td><<RECHTS>></td>
</tr>
</table>
 
..LINKS>>
Linke Zelle
<<..
 
..RECHTS>>
Rechte Zelle
<<..
 
..MITTE>>
Mittlere Zelle
<<..

Die meisten Leser werden sich nun fragen, wozu man einen solchen Mechanismus verwenden könnte. Die Frage ist berechtigt, denn die Möglichkeiten erschließen sich nicht sofort. Man kann (und das ist wohl die Hauptanwendung dieser Funktion) damit das Design einer Site vollkommen von den Inhalten trennen. Damit sind alle Inhalte gekapselt und das Design und die Navigation kann unabhängig von ihnen bearbeitet werden. Im Klartext bedeutet dies, dass für eine Änderung am Design oder der Navigation einer Website im Idealfall nur eine einzige Datei tatsächlich verändert werden muss. Ein Beispiel dafür werden wir weiter unten betrachten.

Das folgende HTML-Fixup korrigiert und erweitert die bestehende HTML-Syntax. Dazu gehören fehlende width- und height-Attribute, die WML direkt aus den angegebenen Bilder extrahiert, Anführungszeichen bei Tag-Argumenten werden ergänzt und noch viele weitere kleinere Korrekturen am Originalcode.

Die Slicetechnik

Der letzte Durchlauf erzeugt bedingt mehrere HTML-Ausgabe-Dateien aus einer WML-Quelle. So ist es auf einfachste Weise möglich, mehrsprachige Sites zu erzeugen, ohne mehrere verschiedene Quelldateien für jede endgültige HTML-Datei zu verwalten:

[EN:Welcome to:][DE:Wilkommen zum:] LinuxTag 1999.

Das allgemeine Format ist [NAME: Text:]. Die Einzelnen Slices können dann mit NAME referenziert werden:

wml -o DEuUNDEF:deutsch.html eingabe.wml
wml -o ENuUNDEF:englisch.html eingabe.wml

erzeugt dann die deutsche respektive englische Version der Seite.

Ein Beispiel

Die HTML-Seiten dieser CD wurden mit WML erstellt. Die einzelnen Referenten erhielten eine Template-Datei:

#
# Template für das Paper-HTML-File
# wird vom Referenten bearbeitet
#
# $Id: vortrags-paper.wml,v 1.2 1999/03/25 10:56:28 kleinhen Exp $
#

#include <paper.inc>

# Hier kommt der Titel des Vortrags hin. Bitte nur "TITEL" ersetzen
<page_title name="Vorträge - TITEL">

# Nocheinmal der Titel
<titel>TITEL</titel>

# Der Autor des Papers, Format: Vorname Nachname (E-Mail)
<autor>Vorname Nachname (user@host.domain.tld)</autor>

# Hier nochmal das Abstract in Kurzfassung, maximal 5-6 Zeilen
<abstract>
Hier kommt der Abstract
</abstract>

<paper>

# Ab hier dann das Paper als Plain-HTML
#
# ERLAUBT SIND: Tables, Ueberschriften, Schriftstyles
#
# _NICHT_ ERLAUBT sind: Frames, Java, Javascript oder andere Skriptsprachen,
#                       Font-Tags, Header-Tags usw.
#
# Zusatztags: <ltimage name="bild.gif" alt="Alternativtext">
#                    Fuegt ein Bild ein. Bitte NUR diesen Tag fuer
#                    Bilder verwenden. 
#

<h1>Wie alles beginnt...</h1>

Hier kommt dann der Paper-Text.. in Plain-HTML!.

# Ende des Papers

</paper>

Hier wurde stark von selbstdefinierten Tags Gebrauch gemacht. Der <ltimage>-Tag vereinheitlicht die Einbindung von Bildern, denn die Definition des Tags gibt eine feste Position der Bilder innerhalb des HTML-Trees vor, die zur Zeit der Erstellung des Templates noch nicht bekannt war.

Durch das Einbinden der Datei paper.inc passiert die tatsächliche Magie. Diese Datei enthält nur wenige Zeilen:

#include <support.inc>
#include <navstyle1.inc> name=lt99navbar select=vortrag

In der Include-Datei support.inc werden einige Zusatztags, wie der schon erwähnte <ltimage>, definiert. Interessant wird es erst bei der Datei navstyle1.inc. Der Name verrät schon, dass man diese Datei einfach auswechseln kann und dadurch völlig unterschiedliche Designs und Navigationskonzepte global für die gesamte Site festlegen kann. Ein einfacher Rebuilt der HTML-Dateien aus den WML-Sourcen genügt.

Bemerkenswert ist auch, dass die Inhaltsverzeichnisse, die sich am Anfang jedes Vortragstextes befinden, automatisch aus den Sourcen erzeugt werden. Die Definition von <paper> sieht dazu folgendermaßen aus:

<define-container paper>
<p>
<font size=+2><b>Inhalt</b></font>
<p>
<toc>
%body
</define-container>

Das Schlüsselwort <toc> generiert aus den Anweisungen <H1>, <H2> usw. dynamisch das Inhaltsverzeichnis. Dies ist natürlich nur eine von vielen kleinen Erweiterungen und Erleichterungen, die WML enthält. Zum Beispiel implementiert WML für Tabellen ebenfalls eine neue, einfacherere Syntax.

Die Navigation und das Design wird wie bereits oben erwähnt in der Datei navstyle1.inc festgeschrieben:

#
# $Id: navstyle1.inc,v 1.2 1999/03/25 12:41:27 kleinhen Exp $
# navstyle1.inc - Navbar-Style 1 für die LinuxTag'99-CD Webseiten 
#
# Dies ist aus Platzgründen eine stark verkürzte Version

(Zunächst werden alle nötigen WML-Funktionen eingefügt.)

#use wml::std::tags
#use wml::std::page
#use wml::std::info
#use wml::std::href
#use wml::des::space
#use wml::des::rollover
#use wml::des::navbar

[PAGE_HEAD:\
   <page    vlink      = "#6060a0"
                link       = "#6060c0"
                alink      = "#6060f0"
                bgcolor    = "#c8c8ff"
                background = "gfx1/background.gif"
                title="<<PAGE_TITLE>>">
<head>
<<PAGE_HEAD>>
</head>

(Hier wird das Banner, das sich über jeder Seite befindet, eingebunden. Dieses Banner ist für jede Seite verschieden, deswegen wird das Bild in Abhängigkeit der Variable $(select) gewählt, die in der Include-Datei paper.inc (siehe weiter oben) gesetzt wurde. Für andere Seiten, z.B. die Software oder Distributionsanleitungen wird select auf einen anderen Wert gesetzt und dadurch das Banner ausgewechselt. In unserem Fall handelt es sich allerdings um Vortragspapers, die alle das gleiche Banner bekommen, deswegen der fest eingestellte Wert vortrag in paper.inc.)

<img src="gfx1/header-$(select).gif" alt="<<PAGE_TITLE>>" border=0><br>

(Als Nächstes wird die Navigationsleiste aufgebaut. Dazu stellt WML ein Modul (navbar) bereit, das zusammen mit dem Modul rollover ein JavaScript-gesteuertes Rollover-Menü bereitstellt. Der Parameter imgstar gibt dazu die Stern-Ersetzung im IMG-Tag der Menüeinträge in Abhängigkeit von "Normal", "Selektiert" und "Maus darüber" an.)

<navbar:define name=lt99navbar
                    imgstar="n:s:o"
                    imgbase="gfx1/"
                    urlbase="">

<navbar:header></navbar:header>
<navbar:prolog></navbar:prolog>

(Hier werden dann die tatsächlichen Menüeinträge definiert. Neben dem URL und dem Alternativtext kommt hier auch der imgstar zum Zuge: Ist der Button selektiert, wird das Bild button-s-hauptseite.gif angezeigt, ist der Button nicht selektiert, und auch der Mauszeiger befindet sich nicht darüber, wird button-n-hauptseite.gif angezeigt. Ist der Mauszeiger darüber, dann button-o-hauptseite.gif.)

<navbar:button id=hauptseite url=index.html txt="Hauptseite" \
               img=button-*-hauptseite.gif>
<navbar:button id=vortraege url=vortraege.html \
               txt="Vortraege" img=button-*-vortraege.gif>

<navbar:epilog></navbar:epilog>
<navbar:footer></navbar:footer>

</navbar:define>

(Die Definition der Navigationsleiste ist nun abgeschlossen. Um sie darzustellen wird der nächste Befehl angegeben. Die Navbar bekommt dann auch einen Namen und die select-Variable wird ihr übergeben.)

<navbar:render name=lt99navbar select=>

:PAGE_HEAD]

(Die Definition des Seitenkopfes ist damit ebenfalls abgeschlossen. Natürlich würden in einer realen Anwendung vorher noch einige Design und Grafikelemente positioniert. Zwischen die beiden Kommentare wird beim WML-Lauf nun der Inhalt der inkludierenden WML-Datei eingefügt. Das Label PAGE_BODY wird übrigends in der letzten Zeile dieser Include-Date definiert.)

<!-- BEGIN OF ACTUAL PAGE CONTENTS -->
 
[PAGE_BODY:
<<PAGE_BODY>>
:PAGE_BODY]
 
<!-- END OF ACTUAL PAGE CONTENTS -->

[PAGE_FOOT:
<<PAGE_PRELOADS>>
:PAGE_FOOT]

(Es folgen noch einige wichtige Zusatzfunktionen.)

<define-tag page_title>
  <preserve name>
  <set-var %attributes>
  ..PAGE_TITLE>><get-var name><<..
  <restore name>
</define-tag>
 
<define-container page_preloads>
  ..PAGE_PRELOADS>>%body<<..
</define-container>
 
..PAGE_BODY>>

Der geneigte Leser wird jetzt sicherlich auch feststellen, warum in den Alternativtext des Banners und in den Seitennamen immer der richtige Seitenname erscheint.

Wie man erkennt, ist alles, was mit der Navbar und dem Seitendesign zu tun hat, in diesem Include-File definiert. Möchte der Webmaster das Design verändern, passt er einfach diese Datei seinen Wünschen an und baut den HTML-Baum neu aus den WML-Quellen. Danach besitzt jede Seite das neue Design. Der Traum ist wahr geworden!

Natürlich konnte ich in der Kürze dieses Textes nicht jedes Feature von WML ansprechen, deswegen empfehle ich dem interessierten Leser, sich die Webseite des Entwicklers anzusehen, auf der es nicht nur den jeweils aktuellen Quellcode gibt, sondern auch eine Fülle weiterer Beispiele und die ausführliche Dokumentation.