![]() |
XML/XSL/XML-basierte Sprachen:
|
|
| |
| E-Mail: | |
|---|---|
| Homepage-URL: |
Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!
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.
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
(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.
Anzeigebeispiel: So sieht's aus (Datei veranstaltungen.htm)
Anzeigebeispiel: So sieht's aus (Datei veranstaltungen.xml - XML/XSLT-fähiger Browser erforderlich)
<!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>
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>
Falls Sie einen nicht-validierenden XML-Parser verwenden (wie dies z.B. bei Mozilla der Fall ist) und weil ein XSL-Prozessor sich nicht um die um die Validität der XML-Datei kümmert, ist es sogar möglich, ungültige ID-Werte (z.B. Werte, die mit einer Zahl beginnen) zu notieren. Es ist jedoch davon abzuraten, diese Möglichkeit in der Praxis zu nutzen, denn beim Umstieg auf einen validierenden XML-Parser wird dieser solche Fehler melden und die Transformation abbrechen.
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.
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:
<xsl:template match="participant" mode="byevent"> <li><xsl:value-of select="@name"/></li> </xsl:template>
Ein Template wird für jedes Element, auf das es zutrifft, neu instanziiert, deshalb ändert sich das Ziel-Element bei jedem "Durchlauf" des Templates und aus diesem Grund spricht man in diesem Zusammenhang vom gegenwärtigen Element, also von dem Element, das gerade abgearbeitet wird. Instanziieren bedeutet, dass alle Elemente und Attribute, die innerhalb des entsprechenden (z.B.) 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.
Die folgenden Stellen werden empfohlen, um das obige Beispiel besser zu verstehen, oder um weitere Möglichkeiten und Details zu erfahren.
SELFHTML: Darstellung von XML-Daten
XSL Transformations (XSLT) Version 1.0 Deutsche Übersetzung
XML Path Language (XPath) Version 1.0 Deutsche, kommentierte Übersetzung