Websitegestaltung mit Forrest
Index für eine Website
- Wie der Berg zum Propheten kommt
- Ein Parser für die Referenzen
- Struktur der Index-Daten
- XSL zur Tranformation der Index-Daten
Wie der Berg zum Propheten kommt
Nachdem die Reiseberichte zu Schottland immer stärker wuchsen, kam bei uns der Wunsch auf, diese Berichte nicht nur chronologisch zu organisieren. Uns kamen vor allem zwei Übersichten in den Sinn:
- Ein Ortsindex für eine Übersicht von Orten, Gegenden, Sehenswürdigkeiten usw. - vor allem gekoppelt mit den Karten, die im letzten Jahr entstanden sind.
- Ein Themenindex für eine Übersicht zu den Schwerpunkten der einzelnen Reiseberichte wir beobachtete Tiere, Landschaften, Häuser, Schlösser usw.
Es stellt sich nur die Frage, wie man dies aufbauen soll, ohne dir Referenzen mit Tippfehlern und Ungenauigkeiten unbrauchbar zu machen. Es wäre sicherlich am Einfachsten, wenn man in der XML-Seite von Forrest mit folgender Zeile auskäme:
<expandindex file="themenindex.xml" />
Dazu gehören zwei Bauteile:
- Ein Parser, der eine passende XML-Struktur schreibt, die an diese Stelle des Dokuments eingefügt wird.
- Eine Erweiterung der XSL-Transformationen, mit denen das generierte Dokument integriert und entsprechend den Wünschen formatiert wird.
Ein Parser für die Referenzen
Eine Warnung vorab: der Code für den Parser ist extrem an unsere Bedürfnissen angepasst und wird nur in seltenen Fällen für jemand anderen einfach wiederverwendbar sein. Wer möchte, kann sich den Sourcecode gerne anschauen und seinen Wünschen entsprechend anpassen.
In der Folge ein paar kurze Informationen, wie ich das Problem gelöst habe:
Durchsuchen der XML-Sourcen
Eines der häufigsten Probleme, das bei einem größeren Projekt auf einen zukommt, ist, an die Liste der zu bearbeitenden Files zu kommen. Ant ist für diese Arbeit wie geschaffen, da es schon vorgefertigte Klassen anbietet, die mit Listen von Files arbeiten.
build.xml
<refbuilder basedir="${src.dir}" destdir="${dest.dir}" includes="reiseberichte/schottland*/*.xml" excludes="**/book.xml"> </refbuilder>
RefBuilderTask.java
public class RefBuilderTask extends MatchingTask { private File basedir; private File destdir; public void execute() throws BuildException { verifyValues(); DirectoryScanner ds = getDirectoryScanner(basedir); String[] files = ds.getIncludedFiles(); ... } public void setBasedir(File basedir) { this.basedir = basedir; } public void setDestdir(File destdir) { this.destdir = destdir; } }
Mit dem geringen Aufwand erhält man einen Array von Strings, der die relativen Pfade und Namen zu den zu parsenden XML-Files enthält.
Finden der Index-Tags
Das Parsen von XML ist an sich eine problemlose Angelegenheit. Es gibt für diesen Zweck den DOM- und den SAX-Parser. Ich bevorzuge für diese einfachen Probleme den SAX-Parser, weil mich die tatsächliche Struktur nur begrenzt interessiert - der Parser soll nur mitbekommen, wenn das passende Tag in der XML-Source auftaucht.
<index entry="National_Driver_Information_and_Control_System" />
Das Tag hat eine einfache Struktur ohne Inhalt. Der Text des Attributs entry wird mit Unterstrichen getrennt, damit man den Text auch für <a name="..."> nutzen kann, wenn an eine bestimmte Stelle innerhalb der Seite gesprungen werden soll.
Für den Handler des SAX-Parser muss man im Sourcecode selbst nachschauen, aber es sei hier gesagt, dass der Parser mit einer ziemlichen Menge Kommentaren nur um die 200 Zeilen lang ist - also beim besten Willen nicht zu kompliziert für jemanden, der schon einmal Java gesehen hat.
Struktur der Index-Daten
Die Möglichkeiten von XSL sind begrenzt. Deswegen sind die Index-Daten recht mundgerecht für die Darstellung. Es war von Anfang an klar, dass der Index auf jeden Fall Einsprungpunkte haben muss, um bei größeren Indices zumindest zu einem Buchstaben springen zu können. Damit ergab sich eine Struktur wie folgt:
<?xml version="1.0" encoding="iso-8859-1"?> <index> <letter name="A"> <entry name="Abendstimmungen" shortname="Abendstimmungen"> <reference source="/.../e_nach_islay.html#idx_Abendstimmungen" title="Abendfähre..." /> </entry> </letter> </index>
Der Index ist nach Buchstaben (letter) und Einträgen (entry) strukturiert. Zu jedem Eintrag können mehrere Referenzen zu den Reiseberichten existieren. Diese Daten sind genauso, wie sie für den Aufbau des Index' benötigt werden.
XSL zur Tranformation der Index-Daten
Die benötigten Erweiterungen sind wieder in dem File document-to-html.xsl vorzunehmen.
<!-- Index --> <xsl:template match="expandindex"> <xsl:variable name="file" select="concat('../../../../crossrefs/',@file)" /> <xsl:apply-templates select="document($file)/index" mode="insertindex" /> </xsl:template> <xsl:template match="index" mode="insertindex"> <div class="indexletters"> <xsl:for-each select="letter"> <xsl:choose> <xsl:when test="position()=1"></xsl:when> <xsl:otherwise>·</xsl:otherwise> </xsl:choose> <xsl:call-template name="indexletter" /> </xsl:for-each> </div> <xsl:apply-templates select="letter" mode="insertindex" /> </xsl:template> <xsl:template name="indexletter"> <a href="#{@name}"> <xsl:value-of select="@name"/> </a> </xsl:template> <xsl:template match="letter" mode="insertindex"> <h3> <span class="toplink"> <a href="#top"> <img src="/skin/images/nav_top.gif" class="navimg" alt="nach oben" title="nach oben" /> </a> </span> <a name="{@name}" /><xsl:value-of select="@name" /></h3> <xsl:apply-templates select="entry" mode="insertindex" /> </xsl:template> <xsl:template match="entry" mode="insertindex"> <dl class="idxentry"> <dt> <a name="{@shortname}"><xsl:value-of select="@name" /></a> </dt> <dd> <ul> <xsl:apply-templates select="reference" mode="insertindex" /> </ul> </dd> </dl> </xsl:template> <xsl:template match="reference" mode="insertindex"> <li> <a href="{@source}"><xsl:value-of select="@title" /></a> </li> </xsl:template>
Hier wird wieder deutlich, dass die Pfade unserer Entwicklungsumgebung entsprechen, in der wir die Website schreiben. Die Pfade sind teilweise fest verdratet und müssen bei Bedarf angepasst werden. Wichtig bei dem Pfad für das XML-Daten-File ist, dass er relativ zu document-to-html.xsl berechnet wird und nicht relativ zu dem File, in das der Index eingefügt werden soll.
In <xsl:template match="index" mode="insertindex"> wird der erste Teil verwendet, die Buchstabenleiste des Index' aufzubauen. Der Vorteil an dieser Vorgehensweise ist, dass nur die Buchstaben eingetragen werden, die im Index vorkommen.
Der Rest ist eigentlich recht unkompliziert. Die Daten aus dem XML-Daten-File werden passend in die HTML-Tags eingefügt, damit die Darstellung den Wünschen entspricht.
Ich hoffe, dass die Beispiele eine gute Idee geben, wie man die Erstellung einer Website für den Autor gleichzeitig erleichtern und die Übersicht über die Daten gleichzeitig verbessern kann.
Viel Spaß beim Ausprobieren!