info@a-coding-project.de

XPath: Pfade bestimmen

Um auf einen Knoten zeigen zu können, wird vom aktuellen Knoten aus ein bestimmter Pfad definiert, den der Interpreter abschreiten muss um zu dem jeweiligen Knoten oder der jeweiligen Knotenmenge zu gelangen. XPath definiert dazu eine Reihe von syntaktischen Hilfsmitteln mit denen die Definition solcher Pfade möglich ist.

Relative Pfade und absolute Pfade

XPath unterscheidet zwischen relativen und absoluten Pfaden. Ein relativer Pfad geht von dem Knoten aus an dem sich der Interpreter gerade befindet. D.h. befindet sich der Interpreter gerade innerhalb des Elementbaumes geht ein relativer Pfad von diesem Knoten innerhalb des Elementbaums aus und zeigt dann auf einen anderen Knoten/Knotenmenge innerhalb des Baumes.

Jeder Schritt zu einem anderen Knoten oder einer anderen Knotenmenge wird durch ein / von den anderen abgetrennt. Als Beispiel sei folgende XML-Datei gegeben:

<a>
 <b>
 <c></c>
 <c></c>
 </b>
</a>

Befindet sich der Interpreter bereits beim Knoten <b> und möchte von da aus nun auf den ersten Knoten <c> zeigen, so geschieht dies mittels dem Pfad:

child::c[position() = 1]

Das Wort child gefolgt von zwei Doppelpunkten gibt dabei an, dass ein Kindknoten des aktuellen Knotens gesucht wird. Nach dem Doppelpunkt folgt die Angabe des Namens, nach welchem Knoten gesucht wird (der erweiterte Name des Knotens). Innerhalb der eckigen Klammern steht dann die Position des zu suchenden Knotens. Nur child::c allein würde eine Knotenmenge liefern (alle Kindknoten mit dem erweiterten Namen c), deshalb wird so angegeben, dass nur der Knoten an der Position 1 gefunden werden soll.

Möchte man vom Knoten <a> auf eben diesen ersten <c>-Knoten zeigen, so geschieht dies durch zwei Schritte, die dementsprechend durch ein / getrennt werden:

child::b[position() = 1]/child::c[position() = 1]

Absolute Pfade sind Pfade die vom Rootknoten ausgehen. Sie beginnen immer mit einem / gefolgt vom (absoluten) Pfad zum entsprechenden Zielknoten/Zielknotenmenge. D.h. egal an welcher Stelle innerhalb des Elementbaums der Interpreter steckt mittels des folgenden Pfades gelang man immer zum ersten <c>-Knoten:

/child::b[position() = 1]/child::c[position() = 1]

Schritte definieren

Wie oben schon annähernd deutlich geworden ist, lassen sich die einzelnen Schritte die zu dem nächsten Knoten innerhalb des Pfades führen sehr exakt definieren. XPath liefert dazu eine Reihe von Hilfsmitteln mit denen ein Schritt sehr genau definiert werden kann. Jeder Schritt besteht dabei aus der Achse, einem Knotentest sowie optional einem oder mehreren Prädikaten.

Achsen

Für die Beschreibung einer Achse können mehrere durch XPath definierte Wörter verwendet werden. Die folgende Tabelle listet diese Wörter auf und verwendet als Grundlage der Beschreibung den folgenden Quellcode:

<a>            [a1]
 <b>           [b1]
  <c />        [c1] 
  <c />        [c2] 
  <c />        [c3] 
  <c />        [c4]
 </b>
 <b>           [b2]
  <d>          [d1]
   <e />       [e1]
   <e />       [e2]
  </d>
  <d>          [d2]
   <e />       [e3]
   <e />       [e4]
  </d>
 </b>
</a>

AchseBeschreibung
childLiefert alle Kindknoten des aktuellen Knotens. Für den Knoten b2 sind das die Knoten d1 und d2. Kinder sind niemals Attributknoten.
descendantLiefert alle Nachkommen des aktuellen Knotens. Für den Knoten b2 sind das die Knoten d1, e1, e2, d2, e3 und e4. Nachkommen sind niemals Attributknoten.
parentLiefert den Elternknoten (sofern es einen gibt) des aktuellen Knotens. Für den Knoten b2 ist das der Knoten a1, für d2 ist das b2, für e3 ist das d2 usw. Für den Elternknoten von a1 wird nichts ausgegeben.
ancestorLiefert alle Vorfahren (sofern es sie gibt) des aktuellen Knotens. Für den Knoten d2 sind das die Knoten b2 und a1, für e1 sind das d1, b2 und a1 usw.
following-siblingLiefert alle nachfolgenden Geschwisterknoten des aktuellen Knotens. Für den Knoten b1 ist das der Knoten b2. Für c1 ist das c2, c3 und c4. Der Knoten c4 hat keine entsprechenden Knoten.
preceding-siblingLiefert alle vorhergehenden Geschwisterknoten des aktuellen Knotens. Für den Knoten c4 sind das die Knoten c3, c2 und c1. Für c1 gibt es keinen solchen Knoten.
followingLiefert alle Knoten die nachfolgende Geschwisterknoten oder deren Nachkommen sind. Für den Knoten b1 sind das: b2, d1, e1, e2, d2, e3 und e4.
precedingLiefert alle Knoten die innerhalb der Dokumentstruktur vor dem aktuellen Knoten liegen aber keine Vorfahren des aktuellen Knotens sind. Für den Knoten e4 sind das: e3, d1, e1, e2, b1, c1, c2, c3 und c4
attributeLiefert alle Attributknoten des aktuellen Knotens. Dies gibt nur bei Elementknoten einen Erfolg aus.
namespaceLiefert alle Namensraumknoten des aktuellen Knotens. Dies gibt nur bei Elementknoten einen Erfolg aus.
selfLiefert den aktuellen Knoten.
descendant-or-selfLiefert alle Knoten die Nachkommen oder der aktuelle Knoten selbst sind. Für den Knoten d2 sind das die Knoten d2, e3 und e4.
ancestor-or-selfLiefert alle Knoten die Vorfahren oder der aktuelle Knoten selbst sind. Für den Knoten d2 sind das d2, b2 und a1.
Bitte beachten Sie, dass nach jedem dieser Worte zwei Doppelpunkte folgen müssen damit die Unterscheidung zwischen Elementnamen und diesen Namen gegeben ist.

Knotentests

Mit Hilfe von Knotentests läßt sich die Suche nach dem gewünschten Knoten oder der gewünschten Knotenmenge noch näher beschreiben. Ein Knotentest ist dabei nichts weiter als eine zusätzliche Definition zu den oben genannten Achsendefinitionen. Als Knotentest können folgende Werte verwendet werden:

  • Knotenname - Wird ein Name angegeben, so wird innerhalb der Knotenmenge aus der Achsendefinition nach den Knoten gesucht die über einen solchen erweiterten Namen verfügen. Als Resultat erhält man damit die Knotenmenge der Knoten mit dem entsprechenden erweiterten Namen.
  • * - Der Stern bedeutet, dass alle Knoten innerhalb der Knotenmenge der Achsendefinition gefunden werden sollen - egal welchen Namen sie tragen.
  • Präfix:Name oder Präfix:* - Bei Angabe eines Präfixes wird nach allen Knoten aus dem entsprechenden Namensraum gesucht die den angegebenen Namen erfüllen. Alternativ kann auch der Stern statt dem Namen verwendet werden - dann werden alle Knoten des Namensraums gefunden - egal welchen Namen sie tragen.
  • text() - Wählt alle Textknoten aus.
  • comment() - Wählt alle Kommentarknoten aus.
  • processing-instruction() - Wählt alle PI-Knoten aus. Optional kann als Parameter innerhalb der Klammern der Name der zu suchenden PI angegeben werden. processing-instruction('xml-stylesheet') findet alle PI's mit dem Namen xml-stylesheet.
  • node() - Wählt alle Knoten beliebigen Typs aus.
Beispiel:

child::a
    wählt alle Kindknoten mit dem Namen a aus

child::*
    wählt alle Kindknoten aus

child::xhtml:h1
    wählt alle Kindknoten aus dem XHTML-Namensraum aus, die h1 
    heissen

Prädikate

Prädikate dienen noch einmal der Verfeinerung einer Suche. Sie sind optional, werden dann aber immer in eckigen Klammern ( [ und ] ) notiert. Innerhalb dieser Klammern kann ein nahezu beliebiger Ausdruck stehen der eine gültige Aussage liefert. Beispiel:

child::a[position() = 1]
    wählt nur das erste Kindelement a aus.

child::a[last()]
    wählt nur das letzte Kindelement a aus.

child::a[attribute::href = "/ziel.htm"]
    wählt die Kindelemente a aus die ein Attribut href="/ziel.htm" 
    besitzen.

Verkürzung der Schreibweise

Da einige Formulierungen öfter verwendet werden, gibt es für diese verkürzte Schreibweisen.

child:: weglassen

Da oftmals auf die Kindelemente des aktuellen Knotens zugegriffen werden muss, kann man sich dies vereinfachen indem man child:: wegläßt. Man beginnt dann mit dem Knotennamen des zu suchenden Kindes. Beispiel:
Lang: child::a/child::b/child::c
Kurz: a/b/c

/descendant-or-self::node()/ verkürzen

Des öfteren werden auch alle Nachkommenknoten verwendet. Um die relativ lange Schreibung von /descendant-or-self::node()/ zu verkürzen kann hierfür einfach nur // notiert werden. Beispiel:
Lang: /descendant-or-self::node()/a
Kurz: //a

Attribute auswählen

Zur Auswahl eines Attributes kann statt der Schreibung attribute::Name das @-Zeichen verwendet werden. Es steht stellvertretend für attribute::. Beispiel:
Lang: child::a[attribute::href = "/ziel.htm"]
Kurz: a[@href = "/ziel.htm"]

Aktueller Knoten

Der aktuelle Knoten wird normalerweise mit self::node() ausgewählt. Um diese Schreibung zu verkürzen kann, statt dessen der Punkt (.) verwendet werden. Beispiel:
Lang: self::node()/parent::a
Kurz: ./parent::a

Elternknoten

Der Elternknoten wird normalerweise mit parent::node() ausgewählt. Um diese Schreibung zu verkürzen, kann statt dessen der doppelte Punkt (.. / nicht verwechseln mit dem Doppelpunkt) verwendet werden. Beispiel:
Lang: parent::node()/a
Kurz: ../a

Weiterlesen: ⯈ Funktionen

Über uns

Stefan Wienströer

Wir entwickeln Webanwendungen mit viel Leidenschaft. Unser Wissen geben wir dabei gerne weiter. Mehr über a coding project

Auch interessant