XML/XSL/XSLT/Elemente gruppieren durch Referenzierung von ID-Werten
Dieser Artikel von Thomas J. Sebestyen erschien am 09.05.2004 im Selfhtml-aktuell-Bereich. Im vorliegenden Artikel wird der oft gestellten Frage nachgegangen, wie man auf die in einer XML-Datei als ID notierten Attribute zugreifen und diese für die Referenzierung und Gruppierung von Elementen bei der Ausgabe verwenden kann. Für das Verständnis dieses Artikels sind Grundkenntnisse in XML und XSLT Voraussetzung.
Inhaltsverzeichnis
Beispiel mit Erläuterungen
Das Beispiel zeigt eine XML-Datei, in der verschiedene Veranstaltungen und die Teilnehmer, die diese besuchen, aufgelistet sind. Die Beziehung zwischen den Veranstaltungen und den Teilnehmern wird durch die Attribute id
und events (IDREF) hergestellt.
Die gewünschte Ausgabe sollte einerseits die jeweilige Veranstaltung und ihre Teilnehmer auflisten, anderseits sollte es auch eine Liste der Teilnehmer mit den von ihnen besuchten Veranstaltungen geben.
<!ELEMENT activity (events,participants)>
<!ELEMENT events (event)+>
<!ELEMENT event EMPTY>
<!ATTLIST event
id ID #REQUIRED
name CDATA #REQUIRED>
<!ELEMENT participants (participant)+>
<!ELEMENT participant EMPTY>
<!ATTLIST participant
events IDREFS #REQUIRED
name CDATA #REQUIRED>
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="veranstaltungen.xsl"?>
<!DOCTYPE activity SYSTEM "veranstaltungen.dtd">
<activity>
<events>
<event id="e01" name="XML on Stage"/>
<event id="e02" name="SELFHTML Treffen"/>
<event id="e03" name="Expertenchat"/>
</events>
<participants>
<participant events="e02" name="Otto Lieb"/>
<participant events="e02" name="Axel Bravo"/>
<participant events="e01 e03" name="Petra Klug"/>
<participant events="e02 e03" name="Birgit Lob"/>
<participant events="e01 e03" name="Andrea Groß"/>
<participant events="e01 e02 e03" name="Heinrich Aller"/>
<participant events="e01 e02 e03" name="Jessy Keen"/>
</participants>
</activity>
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:output
method="html"
encoding="iso-8859-1"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
indent="yes" />
<xsl:key name="participant2event" match="participant" use="id(@events)/@id" />
<xsl:template match="/activity">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>Veranstaltungen und Teilnehmer</title>
</head>
<body>
<h1>Veranstaltungen und Teilnehmer</h1>
<h2>Pro Veranstaltung</h2>
<xsl:apply-templates select="events" />
<hr />
<h2>Pro Teilnehmer</h2>
<xsl:apply-templates select="participants" />
</body>
</html>
</xsl:template>
<xsl:template match="event">
<h3><xsl:value-of select="@name"/></h3>
<ul>
<xsl:apply-templates select="key('participant2event', @id)" mode="byevent"/>
</ul>
</xsl:template>
<xsl:template match="participant">
<p>
<strong><xsl:value-of select="@name"/>: </strong>
<xsl:apply-templates select="id(@events)" mode="byparticipant"/>
</p>
</xsl:template>
<xsl:template match="event" mode="byparticipant">
<xsl:value-of select="@name"/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:template>
<xsl:template match="participant" mode="byevent">
<li><xsl:value-of select="@name"/></li>
</xsl:template>
</xsl:stylesheet>
Erläuterung zu XML und DTD
In unserem Beispiel verwenden wir eine komplette DTD, in der Praxis ist es jedoch oft der Fall, dass für die XML-Datei zwar keine DTD existiert, dennoch Elemente mit Attributen versehen werden, die eine ID-Funktion erfüllen bzw. erfüllen sollen. Aus der Sicht des XSL-Prozessors ist es nicht nötig, dass eine komplette DTD vorhanden ist. Es genügt lediglich, dem Prozessor mitzuteilen, welches Attribut vom Typ ID ist. So können Sie in unserem Beispiel-XML, statt auf eine externe DTD zu verweisen, eine interne DTD-Untermenge verwenden.
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="veranstaltungen.xsl"?>
<!DOCTYPE activity [
<!ELEMENT event EMPTY>
<!ATTLIST event id ID #REQUIRED>
]>
<activity>
...
</activity>
Da der Mozilla Browser einen nicht-validierenden XML-Parser verwendet und somit keine extenen Entities (wie etwa eine DTD) auflösen kann, müssen Sie – falls Sie direkt Ihre XML-Dateien im Internet anbieten – für diesen Browser die Attribut-Deklaration auf alle Fälle (also auch dann, wenn Sie eine externe DTD benutzen!) in der internen DTD-Untermenge notieren.
Erläuterung zu XSLT
In unserem XSL definieren wir zuerst einen key, der auf die participant-Elemente im XML zugreift und als Wert des Schlüssels den XPath-Ausdruck id(@events)/@id verwendet.
Dieser Ausdruck verwendet die id()-Funktion für das Attribut events
im participant
-Element. Dadurch werden die in diesem Attribut angegebenen Werte als ID-Referenzen auf andere Elemente im XML-Dokument erkannt. Durch die Angabe /@id
wird dann die Verknüpfung zu den referenzierten Elementen, genauer gesagt mit deren id-Attribut, hergestellt. Somit enthält dieser key
für jedes participant
-Element das referenzierte event
-Element bzw. die referenzierten event
-Elemente.
Die nächsten wichtigen Schritte sind, die Templates für die beiden Elemente event
und participant
zu definieren.
<xsl:template match="event">
<h3><xsl:value-of select="@name"/></h3>
<ul>
<xsl:apply-templates select="key('participant2event', @id)" mode="byevent"/>
</ul>
</xsl:template>
In diesem Template wird nach der Ausgabe des Namens des events
eine Aufzählungsliste erstellt. In dieser Liste wird dann mit Hilfe des apply-templates-Elements ein anderes Template mit dem Modus "byevent
" instanziiert.
Das select-Attribut in diesem apply-templates-Element benutzt die XPath-Funktion key(). Diese greift auf unseren, mit dem Namen participant2event
definierten, key
zu und als Vergleichs- oder Referenzwert benutzt sie dabei das id
-Attribut im gegenwärtigen event
-Element.
Das bedeutet, dass hier ein Template mit dem Modus "byevent" für diejenige participant-Elemente gesucht und ausgeführt wird, in deren event-Attribut der Wert des id-Attributs des gegenwärtigen event-Elements vorhanden ist. Beim event "XML on Stage" sind dies die Elemente:
<participant events="e01 e03" name="Petra Klug" />
<participant events="e01 e03" name="Andrea Groß" />
<participant events="e01 e02 e03" name="Heinrich Aller" />
<participant events="e01 e02 e03" name="Jessy Keen" />
Das Template für diese Elemente erstellt nur einen Listenpunkt, der den Namen des Teilnehmers enthält:
{{Beispiel|titel=|
{{BeispielCode|<syntaxhighlight lang="xml">
<xsl:template match="participant" mode="byevent">
<li><xsl:value-of select="@name"/></li>
</xsl:template>
xsl:template
-Elements stehen und nicht zum XSLT-Namensraum gehören, in den Ergebnisbaum geschrieben werden.Das Template für das participant-Element sieht etwas anders aus:
<xsl:template match="participant">
<p>
<strong><xsl:value-of select="@name"/>: </strong>
<xsl:apply-templates select="id(@events)" mode="byparticipant"/>
</p>
</xsl:template>
Hier wird für jedes participant-Element ein Absatz erzeugt und der Name des Teilnehmers in fetter Schrift ausgegeben. Danach wird wiederum ein apply-templates-Element, diesmal mit dem Modus "byparticipant", aufgerufen. Gesucht und ausgeführt wird ein Template für event-Elemente durch die id()-Funktion, die im event-Attribut des gegenwärtigen participant-Elements referenziert ist. Beim Teilnehmer "Petra Klug" sind dies die Elemente:
<event id="e01" name="XML on Stage" />
<event id="e03" name="Expertenchat" />
Das Template für diese Elemente gibt einfach den Namen der Veranstaltung aus und wenn diese nicht die letzte in der Reihe ist, fügt es nach dem Namen ein Komma und ein Leerzeichen ein.
<xsl:template match="event" mode="byparticipant">
<xsl:value-of select="@name"/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:template>
Das Template für das activity-Element (<xsl:template match="/activity">) enthält das Grundgerüst für die HTML-Seite und ruft an den entsprechenden Stellen die normalen Templates für Veranstaltungen und Teilnehmer auf.
Weblinks
Deutsche Übersetzung 18. März 2002
Version 1.0 Deutsche, kommentierte Übersetzung 26. Februar 2002