• Keine Ergebnisse gefunden

4   Die Transformationssprache XSLT   41

4.3 XPath

XSLT bedient sich zur Navigation innerhalb des XML-Eingabedokuments der Sprache XPath. Diese beinhaltet zwar ebenfalls logische und arithmetische Ausdrücke, den wichtigsten Bestandteil stellen jedoch die Pfadausdrücke dar. Mit ihnen kann auf jeden beliebigen Knoten des Eingabedokumentes zugegriffen werden. Das Beispiel in Lis-ting 3 auf Seite 43 enthält nur den Pfadausdruck @quelle (Zeile 7), der auf das quelle-Attribut zugreift. Ausgangspunkt eines solchen Pfades ist dabei der so ge-nannte Kontextknoten, der in diesem Beispiel ein faq-Element ist. Dies ist der Knoten, für den das Template ausgeführt wird. Der Aufbau von Pfadausdrücken wird im Folgenden genauer vorgestellt.

Ein Pfad kann aus mehreren Schritten zusammengesetzt werden, die durch Schräg-striche (slashes) voneinander getrennt sind. Jeder Schritt wiederum besteht aus einer optionalen Achse, einem Knotentest und einer ebenfalls optionalen Liste von Prädi-katen:

Achse::Knotentest Prädikate

Die Achse gibt an, in welche Richtung innerhalb des Eingabebaumes navigiert werden soll. Mit Hilfe des Knotentests werden diverse Knotentypen unterschieden. Die Liste der Prädikate dient schließlich dem Test weiterer Eigenschaften, denen die ausge-wählten Knoten genügen müssen.

Achsen XPath definiert 13 verschiedene Achsen:

Tabelle 1

Knoten, die dem Kontextknoten vorangehen preceding

Knoten, die dem Kontextknoten folgen following

Dissertation, Oliver Becker, 1. Juli 2004

4.3  XPath 45

Attribute attribute

Namensräume namespace

Die letzten beiden Achsen nehmen eine Sonderrolle ein, da über sie nur spezielle Knotentypen ausgewählt werden: Attributknoten bzw. Namensraumknoten. Alle an-deren Achsen (von self abgesehen) enthalten niemals Knoten dieser beiden Kno-tentypen. Abbildung 2 zeigt 9 der 13 Achsen. Die jeweils ausgewählte Knotenmenge ist durch eine gestrichelte Linie umrandet. Der Kontextknoten ist im Bild durch die Achse self gekennzeichnet.

Abbildung 2 Einige

XPath-Achsen

sibling

preceding-sibling following-self

child

following ancestor

parent preceding

descendant

Die Achse child ist die Vorgabeachse. Sie kann daher inklusive der beiden Doppel-punkte weggelassen werden. Die Attributachse lässt sich durch das Zeichen @ abkür-zen. Der genannte Beispielpfad @quelle steht damit für attribute::quelle.

Knotentests Ein Knotentest bestimmt den gewünschten Knotentyp. Neben den bereits genannten Attribut- und Namensraumknoten unterscheidet das XPath-Datenmodell fünf weitere Knotentypen, die im Folgenden aufgelistet werden:

Tabelle 2 XPath-Knotentests

Knotentest Knotentyp

Element * ein beliebiges Element

ein foo-Element.

foo

ein Element aus dem durch ns bezeichneten Namensraum ns:*

ein foo-Element aus dem durch ns bezeichneten Namensraum ns:foo

text() Textknoten

comment() Kommentarknoten

processing-instruction() Verarbeitungsanweisung

processing-instruction(String) kein spezieller Knotentest

Dokumentknoten

Serielle Transformationen von XML. Probleme, Methoden, Lösungen.

46 4  Die Transformationssprache XSLT

Auf der und Namensraumachse würden *, foo, ns:* und ns:foo Attribut-bzw. Namensraumknoten mit den entsprechenden Namen auswählen.4 Den Doku-mentknoten erreicht man über den Pfad / (ein einzelner Schrägstrich). Ein Pfad, der mit einem Schrägstrich beginnt, wird absoluter Pfad genannt und immer vom Doku-mentknoten her ausgewertet. Der Knotentest node() passt schließlich auf alle Knoten unabhängig von ihrem Typ.

Möchte man beispielsweise im Template für frage auf das quelle-Attribut von faq zugreifen, so würde der Pfad parent::faq/attribute::quelle zum

Abkürzungen Ziel führen. Praktischerweise kennt XPath neben @ weitere Abkürzungen, sodass

sich als wesentlich kompakterer Ausdruck ../@quelle notieren lässt. Die Abkür-zung .. steht dabei für parent::node(), also für den Elternknoten unabhängig von seinem Typ. Ein einzelner Punkt . bezeichnet den Kontextknoten selbst (self::node()). Die Nachkommen des Kontextknotens lassen sich über die Kurzschreibweise // erreichen, welche für /descendant-or-self::node()/

steht.

Prädikate In jedem Schritt kann schließlich eine Liste von Prädikaten angegeben werden, die

die ausgewählten Knoten weiter selektieren. Ein einzelnes Prädikat besteht dabei aus einem in eckigen Klammern eingeschlossenen XPath-Ausdruck. Für jeden durch den Schritt als Kontextknoten ausgewählten Knoten werden die Ausdrücke in den Prädi-katen ausgewertet. Liefert ein Ausdruck den Booleschen Wert falsch, wird der ent-sprechende Knoten aus der Menge entfernt.

Wenn das Dokument mit dem Wurzelelement faq in der Realität ein Fragment eines größeren Dokuments mit vielen Fragen und Antworten ist, so würde

//faq[antwort/name='Rick Jelliffe']

nur die faq-Elemente auswählen, die von Rick Jelliffe beantwortet wurden. Dieser Pfad beginnt mit einem Schrägstrich und untersucht daher das gesamte Dokument.

Sollen außerdem nur seine Antworten aus dem August des Jahres 2000 betrachtet werden, würde folgender Ausdruck zum Ziel führen

//faq[antwort/name='Rick Jelliffe']

[contains(@quelle,'/200008/')]

Die Funktion contains liefert den Wert wahr, wenn die Zeichenkette des zweiten Parameters im ersten Parameter enthalten ist. Da hier beide Prädikate unabhängig voneinander erfüllt sein müssen, können deren Bedingungen auch innerhalb eines Prädikats miteinander verknüpft werden. Ein äquivalenter Pfadausdruck lautet daher

//faq[antwort/name='Rick Jelliffe' and contains(@quelle,'/200008/')]

Positionen Jeder Knoten besitzt eine Position innerhalb der Liste der ausgewählten Knoten. In

Schritten, die eine vorwärts gerichtete Achse enthalten, werden diese Knoten entspre-chend der Originalreihenfolge im Dokument nummeriert. Eine vorwärts gerichtete Achse enthält dabei nur Knoten, die dem Kontextknoten im Dokument folgen. Enthält der Schritt dagegen eine rückwärts gerichtete Achse, dreht sich diese Reihenfolge um. Der Elternknoten ist somit der erste Knoten auf der Achse ancestor; der di-rekte Vorgänger ist der erste Knoten auf der Achse preceding-sibling usw.

Die Position kann mit Hilfe der Funktion position abgefragt werden:

antwort/absatz[position()=2]

4Dabei ist anzumerken, dass Namensraumknoten selbst keinen qualifizierten Namen besitzen. Das bedeutet, dass namespace::ns:* und namespace::ns:foo niemals einen Knoten auswählen.

Dissertation, Oliver Becker, 1. Juli 2004

4.3  XPath 47

würde den zweiten Absatz der Antwort auswählen. Dagegen würde //absatz[position()=2]

alle Absätze auswählen, die an zweiter Stelle innerhalb ihres Elternelements vorkom-men. Ergibt die Berechnung des Ausdrucks in einem Prädikat eine Zahl, so ist das Prädikat dann erfüllt, wenn diese Zahl mit der aktuellen Position übereinstimmt. Der letzte Ausdruck kann daher kürzer als

//absatz[2]

notiert werden. Durch vorangehende Prädikate ändern sich in der Regel auch die Positionen der betrachteten Knoten. Dazu ebenfalls zwei Beispiele:

//faq[antwort/name='Rick Jelliffe'][2]

liefert das zweite der durch Rick Jelliffe beantworteten faq-Elementen. Dagegen wählt

//faq[2][antwort/name='Rick Jelliffe']

zunächst das zweite faq-Element aus und testet anschließend, ob dieses ebenfalls die folgende Bedingung erfüllt.

Es ist leicht einzusehen, dass eine Liste von Prädikaten, in der höchstens im ersten Prädikat auf die Position zugegriffen wird, äquivalent durch ein einziges Prädikat ausgedrückt werden kann, in dem die einzelnen Ausdrücke mit einem logischen und verbunden werden. Das letzte Beispiel wird damit zu

//faq[position()=2 and antwort/name='Rick Jelliffe']

Muster

Muster (patterns) sind spezielle XPath-Pfadausdrücke. Sie werden in XSLT für die Auswahl eines geeigneten Template mit Hilfe des so genannten Pattern-Matching benutzt. Muster sind deshalb in der XSLT-Spezifikation [W3C99c] und nicht in XPath [W3C99b] beschrieben.

Muster unterscheiden sich syntaktisch von vollen Pfaden dadurch, dass in ihnen ex-plizit nur die beiden Achsen child und attribute verwendet werden können.

Daneben sind jedoch alle Abkürzungen inklusive des doppelten Schrägstriches (//) erlaubt. Innerhalb von Prädikaten können volle XPath-Ausdrücke benutzt werden, mit der Ausnahme, dass diese keine Variablen enthalten dürfen.

Ein Muster passt dann auf einen Knoten, wenn es einen anderen Knoten im Dokument gibt, von dem als gedachter Kontextknoten aus das Muster den betrachteten Knoten auswählen würde. Diese etwas komplizierte Definition beschreibt nur die Semantik, nicht jedoch die Implementation. Tatsächlich kann man ein Muster immer von rechts nach links lesen und im Eingabebaum geeignete Knoten auf der Vorfahrenachse su-chen.

Im Dokument Serielle Transformationen von XML (Seite 57-60)