Der Achsenschritt

(Auszug aus "XSLT 2.0 & XPath 2.0" von Frank Bongers, Kapitel 4.)

Der Achsenschritt wählt ausgehend von Kontextknoten zunächst generell alle Knoten aus, die auf der durch ihn bezeichneten Achse liegen. Dies können beliebig viele, aber auch gar keine (null) Knoten sein, die in Achsenrichtung geordnet sind – also in Abhängigkeit von der gewählten Achse in oder entgegen der Dokumentreihen­folge.

Aus dieser durch die Achse bezeichneten Grundmenge von Kno­ten werden diejenigen behalten, die einen der eben beschriebenen in XPath formulierbaren Knotentests (node tests) bestehen. Die dem Achsenschritt zugrunde liegenden Achsen wurden ebenfalls bereits erläutert.

Für jeden möglichen Achsenschritt existiert eine vollständige Bezeichnung; für einige häufig benötigte darüber hinaus auch eine abgekürzte Syntax.

Achsenschritt: Vollständige Syntax

Unter der sogenannten »vollständigen«, oder, korrekter übersetzt, »unabgekürz­ten« Syntax (unabbreviated syntax) versteht man die Methode, den Achsenbe­zeichner innerhalb eines Achsenschrittes mit seinem vollständigen Namen (Achsenname, gefolgt vom verdoppelten Doppelpunkt) zu verwenden. Sche­matisch sieht das so aus:

achsenname::knotentest

Dieser Syntax ist grundsätzlich für alle dreizehn Achsen einsetzbar; für eine häufig benötigte Teilmenge von ihnen steht alternativ eine Abkürzung zur Ver­fügung (siehe »abgekürzte Syntax«).

Auch den Achsenbezeichnern mit Doppelpunkten folgt ein Nodetest, der den Knotentyp nennt, der durch den Ausdruck auf der entsprechenden Achse aus­gewählt werden soll.

Beispiele:

a) Einfache Pfadausdrücke

Ein einfacher Pfadausdruck besteht aus einem einzelnen Schritt, der aus einem Achsenbezeichner und einem Knoten­test zusammengesetzt ist.

child::* 
wählt alle Elementknoten auf der Child-Achse des Kontext­knotens ungeachtet ihres Bezeichners.

child::mein_element
wählt alle Elementknoten mit Bezeichner mein_element, die Kindknoten des Kontextknotens sind.

child::text() 
wählt alle Textknoten, die Kindknoten des Kontextkno­tens sind.

child::node() 
wählt alle Kindknoten des Kontextknotens ungeachtet ihrer Knotengattung oder ihres Bezeichners, also Elementknoten, Text- und Kommentarknoten sowie Processing-Instruction-Knoten.

attribute::mein_attribut 
wählt einen Attributknoten des Kontext­knotens, der den Bezeichner mein_attribut besitzt (dies ist höchstens ein Knoten).

parent::* 
wählt den Elternknoten des Kontextknotens. Es handelt sich um einen Elementknoten oder den Dokumentknoten. Ist der Kontextknoten ein Attributknoten, so gibt der Ausdruck den Elementknoten zurück, zu dem das Attribut gehört.

descendant::mein_element
wählt alle Elementknoten mit Bezeichner mein_element aus, die auf der Descendant-Achse des Kontextknotens existie­ren, also dessen Nachfahren sind.

ancestor::mein_element
wählt alle Elementknoten mein_element, die Vorfahren des Kontextknoten sind.

ancestor-or-self::mein_element
wählt alle Elementknoten mein_element, die Vorfahren des Kontextknotens sind. Falls es sich beim Kontext­knoten selbst um einen Elementknoten mein_element handelt, wird dieser ebenfalls ausgewählt.

descendant-or-self::mein_element
wählt alle Elementknoten mein_element, die Nachfahren (Kinder und Kindeskinder) des Kontextknotens sind. Falls es sich beim Kontextknoten selbst um einen Elementknoten mein_ele­ment handelt, wird dieser ebenfalls ausgewählt.

self::mein_element
wählt den Kontextknoten aus, falls es sich bei die­sem um einen Elementknoten mein_element handelt. Andernfalls wird nichts gewählt.

b) Zusammengesetzte Pfadausdrücke

Für zusammengesetzte Pfadaus­drücke muss die Achse bei jedem Schritt genannt werden. Entsprechend kann sie von Schritt zu Schritt wechseln.

child::kapitel/descendant::abschnitt
wählt alle Elementknoten abschnitt, die Nachfahren eines Elements kapitel sind, die wiederum Kind­knoten des Kontextknotens sind.

child::*/child::abschnitt
wählt alle Elementknoten abschnitt, die Kindeskinder des Kontextknotens sind. Der Bezeichner des Elements des dazwischen liegenden Schritts ist gleichgültig (Wildcard-Platzhalter), es muss jedoch genau ein dazwischen liegender Schritt vorhanden sein.

/descendant::abschnitt 
wählt alle Elemente abschnitt, die sich im selben Dokumentbaum befinden wie der Kontextknoten. Handelt es sich beim Kontextknoten selbst um ein Element abschnitt, so wird er ebenfalls ausge­wählt.

/descendant::abschnitt/child::ueberschrift
wählt alle Element­knoten ueberschrift aus, die Kindknoten eines Elements abschnitt sind und sich im selben Dokumentbaum wie der Kontextknoten befinden.

Achsenschritte: Abgekürzte Syntax (abbreviated syntax)

Neben der grundsätzlich überall verwendbaren, vollständigen Syntax kann für einige wichtige Achsen anstelle des Achsenbezeichners auch eine Abkürzung innerhalb des Achsenschrittes eingesetzt werden. Folgende Achsen können abgekürzt werden bzw. es existieren in ihrem Zusammenhang Abkürzungen, die für einen kompletten Achsenschritt stehen:

  • Self-Achse
    Es existiert der Platzhalterausdruck ».« (Punkt) für das Kontexti­tem, der innerhalb von Pfadausdrücken dem Achsenschritt self::node() entspricht, in anderem Kontext jedoch sowohl einen Knoten (den Kontext­knoten) als auch einen atomaren Wert (dann ein Kontextitem) bezeichnet. Der Ausdruck ».« ist daher im eigentlichen Sinne keine Abkürzung für die Achse selbst.
  • Child-Achse
    Der Achsenbezeichner für die »Child«-Achse kann innerhalb von Achsenschritten einfach entfallen, da die »Child«-Achse die Default-Achse darstellt. Statt child::mein_element steht daher einfach mein_element, statt child::node() einfach node(). Die abgekürzte Syntax für einen Achsentest auf der »Child«-Achse besteht daher nur aus dem Knotentest.
  • Parent-Achse
    Es existiert der Platzhalterausdruck »..« (zwei Punkte) für den Achsenschritt parent::node(). Dieser Ausdruck ist daher keine eigent­liche Abkürzung für den Achsenbezeichner. Der Ausdruck ../titel ist also eine Abkürzung für parent::node()/child::titel und wählt alle Geschwisterknoten (d.h. Kinder des gleichen Elternknotens) titel des Kon­textknotens und diesen selbst aus, wenn es sich bei ihm um ein Element titel handelt.
  • Attribute-Achse
    Der Achsenbezeichner für die »Attribute«-Achse kann innerhalb eines Achsenschrittes durch die Abkürzung »@« ersetzt werden. Statt attribute::mein_attribut kann einfach @mein_attribut geschrieben werden, statt attribute::* einfach @*. Die abgekürzte Syntax für einen Achsenschritt auf der »Attribute«-Achse besteht daher aus dem @ und einem Knotentest.
  • Descendant-Or-Self-Achse
    Es existiert ein Platzhalterausdruck »//« (zwei Slashes) für den Achsenschritt descendant-or-self::node(). Tritt die Abkürzung // inerhalb eines zusammengesetzten Pfadausdrucks auf, so wird sie effektiv zu /descendant-or-self::node()/ expandiert. Steht sie am Beginn des Pfadausdrucks, so stellt dieser einen absoluten Pfadausdruck dar (nähere Erläuterung unter »Formale Betrachtung von / und //«, siehe unten). Der Doppelslash steht also nicht direkt als Abkürzung für die »Descendant-Or-Self«-Achse selbst.

Beispiele:

mein_element 
wählt alle Kindknoten mein_element des Kontextkno­tens.

*
wählt alle Elementknoten, die Kinder des Kontextknotens sind, unab­hängig von ihren Bezeichnern.

text() 
wählt alle Kindknoten des Kontextknotens, bei denen es sich um Textknoten handelt.

@mein_attribut
wählt das Attribut mit Bezeichner mein_attribut, das zum Kontextknoten gehört.

kapitel[fn:last()] 
wählt das letzte Element kapitel in Dokumen­treihenfolge, das Kind des Kontextknotens ist.

kapitel//abschnitt 
wählt alle Elementknoten mit Bezeichner abschnitt, die von einem Element kapitel abstammen, das Kindknoten des Kontextknotens ist.

/
wählt den Dokumentknoten aus, der unten in der Hierarchie des Baums steht, der den Kontextknoten enthält (nähere Erläuterung dieses Ausdrucks unter »Formale Betrachtung von / und //«, siehe unten).

//abschnitt 
wählt alle Elementknoten abschnitt innerhalb des Dokuments (d.h., die Descendants des Dokumentknotens sind). Ist der Kon­textknoten ein Element abschnitt, so wird er ebenfalls gewählt.

.//abschnitt 
wählt alle Elementknoten abschnitt, die Nachfahren (descendants) des Kontextknotens sind (der Punkt für den Kontextknoten ist in diesem Zusammenhang unverzichtbar). Der Ausdruck würde nicht abgekürzt als self::node()/descendant-or-self::node()/abschnitt geschrieben.

buch/(kapitel | anhang)/abschnitt 
wählt alle Elementknoten abschnitt, die Kindknoten eines Elements kapitel oder anhang sind, welche Kindknoten eines Elements buch sind, das seinerseits Kindknoten des Kontext­knotens ist.

Formale Betrachtung von »/« und »//«

Der Slash »/« am Anfang eines Pfadausdrucks ist ebenso eine Abkürzung wie der Doppelslash »//«. Letzterer setzt, am Anfang des Pfadausdrucks stehend, ebenfalls am Dokumentknoten an und schließt diesen (descendant-or-self) mit ein. Von dort aus reicht er auf der Descendant-Achse beliebig weit in den Dokumentbaum hinein (und erfasst dabei zwangsläufig auch den aktuellen Knoten).

Der einfache Slash:

Bei Licht gesehen ist der beginnende einfache oder der einzeln stehende Slash »/« nicht identisch mit dem Pfadoperator, wie er im Inneren von Pfadausdrücken verwendet wird, sondern steht abkürzend für den Dokumentknoten – formal also für den Schritt:

fn:root(self::node()) treat as document-node()

Erklärung:
Die Funktion fn:root() findet den Wurzelknoten eines Baums (Nicht in allen Fällen ist der mit fn:root() ermittelte Wurzelknoten eines Baums auch ein Dokumentknoten – daher die Notwendigkeit des folgenden Teilausdrucks.), wobei der ihr mittels des Ausdrucks self::node() als Argument übergebene Kontextknoten Teil dieses Baums ist. Zusätzlich wird angeordnet, den so gefundenen Wurzelknoten als Dokumentknoten anzusehen, treat as document-node(), und bei diesem den Pfadausdruck anzusetzen. Der Kontextknoten und seine Position im Dokument spielen daher bei der Ver­ankerung des Ausdrucks keine Rolle.

Hinweis – Keine Typumwandlung durch treat as:
Die Formulierung treat as bedeutet lediglich eine »statische Zusicherung« (assertion). Handelt es sich bei dem so aufgefundenen Knoten in Folge nicht um einen Dokumentknoten, so ergibt sich ein Laufzeitfehler (err:XPDY0050). Eine Umwandlung findet durch treat as nicht statt.

Der doppelte Slash:

Ähnlich dem eben aufgeschlüsselten Ausdrucks steht die Abkürzung »//« für die ausführliche Schrittfolge:

fn:root(self::node()) treat as document-node()/descendant-or-self::node()

Erklärung:
Der doppelte Slash »//« steht für die Achse descendant-or-self und jeden Knoten node(), der an ihrem Ende liegt: descendant-or-self::node(). Am Anfang des Pfadausdrucks stehend bezeichnet auch der Doppelslash einen absoluten Pfad, daher wird der ausführliche Schritt für den einfachen Slash vorangesetzt. Einfacher ausgedrückt stellt »//« in //step_1 eine Ausgangssequenz bestehend aus allen Nodes des Dokumentbaums als Kontext für die Auswertung von step_1 zusammen. Alle Knoten des Baums werden also nacheinander überprüft, ob sie diesen Schritt erfüllen.

   

<< zurück vor >>
Tipp der data2type-Redaktion:
Zum Thema XPath bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © Galileo Press, Bonn 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT 2.0 & XPath 2.0 ― Das umfassende Handbuch" denselben Bestimmungen wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Galileo Press, Rheinwerkallee 4, 53227 Bonn