XML Path Language (XPath)
Version 1.0

Deutsche, kommentierte Übersetzung

10. September 2001

Dies ist die deutsche Übersetzung der W3C-Empfehlung "XML Path Language (XPath)" vom 16. November 1999. Bitte beachten Sie, dass dieses Dokument Übersetzungsfehler enthalten kann. Die normative englische Version des Dokumentes befindet sich unter http://www.w3.org/TR/1999/REC-xpath-19991116

Bitte schicken Sie Fehler in dieser Übersetzung oder Verbesserungsvorschläge an den Übersetzer.

Diese Version:
http://www.obqo.de/w3c-trans/xpath-de-20010910
(verfügbar als XML oder HTML)
Aktuelle Version:
http://www.obqo.de/w3c-trans/xpath-de
Vorherige Version:
http://www.obqo.de/w3c-trans/xpath-de-20010702
Übersetzer:
Oliver Becker <ob@obqo.de>

Dieses Dokument ist urheberrechtlich geschützt, Copyright © 1999 - 2001 W3C® (MIT, INRIA, Keio), alle Rechte vorbehalten. Die Rechte an dieser Übersetzung liegen beim Übersetzer, Copyright © 2001 Oliver Becker.

 
W3C

XML Path Language (XPath)
Version 1.0

Empfehlung des W3C, 16. November 1999

Diese Version:
http://www.w3.org/TR/1999/REC-xpath-19991116
(verfügbar als XML oder HTML)
Aktuelle Version:
http://www.w3.org/TR/xpath
Vorherige Versionen:
http://www.w3.org/TR/1999/PR-xpath-19991008
http://www.w3.org/1999/08/WD-xpath-19990813
http://www.w3.org/1999/07/WD-xpath-19990709
http://www.w3.org/TR/1999/WD-xslt-19990421
Herausgeber:
James Clark <jjc@jclark.com>
Steve DeRose (Inso Corp. and Brown University) <Steven_DeRose@Brown.edu>

Zusammenfassung

Die Sprache XPath dient zur Adressierung von Teilen eines XML-Dokuments. Sie wurde für die Verwendung sowohl in XSLT als auch in XPointer entworfen.

Status dieses Dokuments

Dieses Dokument wurde von Mitgliedern des W3C und anderen Interessierten geprüft und vom Direktor als W3C-Empfehlung gebilligt. Es ist ein abgeschlossenes Dokument und darf als Referenzmaterial verwendet oder als normative Referenz von einem anderen Dokument zitiert werden. Die Rolle des W3C bei der Erstellung dieser Empfehlung ist es, die Spezifikation bekanntzumachen und ihre breite Anwendung zu fördern. Dies erhöht die Funktionsfähigkeit und Interoperabilität des Web.

Die Liste der bekannten Fehler in dieser Spezifikation ist unter http://www.w3.org/1999/11/REC-xpath-19991116-errata verfügbar.

Anmerkungen zu dieser Spezifikation können an www-xpath-comments@w3.org geschickt werden; alle Anmerkungen sind in einem Archiv verfügbar.

Die englische Version dieser Spezifikation ist die einzig normative Version. Allerdings werden Übersetzungen dieses Dokumentes unter http://www.w3.org/Style/XSL/translations.html aufgeführt.

Aktuelle W3C-Empfehlungen und weitere technische Dokumente sind unter http://www.w3.org/TR zu finden.

Diese Spezifikation ist das Ergebnis der gemeinsamen Arbeit der XSL- und der XML-Linking-Arbeitsgruppen und damit Teil der W3C Style Activity und der W3C XML Activity.

Inhaltsverzeichnis

1 Einleitung
2 Lokalisierungspfade
    2.1 Lokalisierungsschritte
    2.2 Achsen
    2.3 Knotentests
    2.4 Prädikate
    2.5 Abgekürzte Syntax
3 Ausdrücke
    3.1 Grundlagen
    3.2 Funktionsaufrufe
    3.3 Knotenmengen
    3.4 Boolesche Werte
    3.5 Zahlen
    3.6 Zeichenketten
    3.7 Lexikalische Struktur
4 Bibliothek der Grundfunktionen
    4.1 Funktionen auf Knotenmengen
    4.2 Zeichenkettenfunktionen
    4.3 Boolesche Funktionen
    4.4 Zahlenfunktionen
5 Datenmodell
    5.1 Wurzelknoten
    5.2 Elementknoten
        5.2.1 Eindeutige IDs
    5.3 Attributknoten
    5.4 Namensraum-Knoten
    5.5 Processing-Instruction-Knoten
    5.6 Kommentarknoten
    5.7 Textknoten
6 Konformität

Anhang

A Referenzen
    A.1 Normative Referenzen
    A.2 Andere Referenzen
B Abbildung auf das XML Information Set (nicht normativ)

1 Einleitung

XPath ist das Ergebnis der Bemühungen, eine gemeinsame Syntax und Semantik für jene Funktionen bereitzustellen, die sowohl von XSL Transformations [XSLT] als auch von XPointer [XPointer] genutzt werden. Die primäre Aufgabe von XPath besteht in der Adressierung von Teilen eines XML-Dokuments [XML]. Zur Unterstützung dieser Aufgabe werden außerdem einfache Hilfsmittel für die Manipulation von Zeichenketten, Zahlen und booleschen Werten bereitgestellt. XPath benutzt eine kompakte nicht-XML-Syntax, um die Verwendung von XPath-Ausdrücken innerhalb von URIs und XML-Attributen zu erleichtern. XPath operiert auf der abstrakten, logischen Struktur eines XML-Dokuments, nicht auf seiner äußerlichen Syntax. Seinen Namen erhält XPath durch die Verwendung einer auch in URLs genutzten Pfad-Notation (path), mit der sich durch die hierarchische Struktur eines XML-Dokuments navigieren lässt.

Neben der Verwendung für die Adressierung wurde XPath so gestaltet, dass eine natürliche Teilmenge davon zum Matching (Testen, ob ein Knoten auf ein Muster passt) genutzt werden kann. Diese Anwendung von XPath ist in XSLT beschrieben.

Anmerkung des Übersetzers:

Diese Teilmenge wird in XSLT Muster (pattern) genannt. Obwohl diese Muster durch eine eigene Grammatik definiert werden, ist jedes Muster auch ein XPath-Ausdruck.

Neben XSLT und XPointer existieren weitere Spezifikationen, die XPath nutzen. Als Beispiel sei hier der Arbeitsentwurf des W3C für die XML-Abfragesprache XQuery [XQuery] genannt, deren Syntax erweitere XPath-Ausdrücke verwendet.

XPath modelliert ein XML-Dokument als einen Baum, der aus Knoten besteht. Es gibt verschiedene Knotentypen, unter anderem Elementknoten, Attributknoten und Textknoten. XPath definiert, wie der Zeichenkettenwert für jeden Knotentyp berechnet wird. Einige Knoten besitzen zusätzlich einen Namen. XPath unterstützt in vollem Umfang XML-Namensräume [XML Names]. Daher wird der Name eines Knotens als ein Paar aus einem lokalem Bestandteil und einem gegebenenfalls leeren Namensraum-URI modelliert - dieses wird erweiterter Name genannt. Das Datenmodell ist detailliert in [5 Datenmodell] beschrieben.

Anmerkung des Übersetzers:

Zur Veranschaulichung der durch XPath modellierten Baumstruktur soll folgendes Beispiel dienen:

<?xml version="1.0"?>
<!DOCTYPE rezept SYSTEM "rezept.dtd">
<?xml-stylesheet href="style.xsl" type="text/xml"?>
<rezept>
   <zutat id="mehl">200g Mehl</zutat>
   <!-- weitere Zutaten -->
   <anleitung>
      Zuerst nehmen Sie das
      <zutat xmlns:xlink="http://www.w3.org/1999/xlink"
             xlink:type="simple" xlink:href="mehl">Mehl</zutat>
      und mischen es mit ...
   </anleitung>
</rezept>

Dieses recht kurze XML-Dokument besitzt bereits eine aus 23 Knoten bestehende Baumrepräsentation:

Baumdarstellung

Die XML-Deklaration sowie die Dokumenttyp-Deklaration finden sich in der Baumdarstellung nicht wieder, auf sie kann über einen XPath-Ausdruck auch nicht zugegriffen werden. Alle anderen Bestandteile des Dokuments (Wurzel, Elemente, Textinhalt, Attribute, Namensräume, Kommentare, Processing Instructions) werden durch entsprechende Knoten des Baumes repräsentiert. Die leeren Quadrate symbolisieren Textknoten, die ausschließlich Leerraumzeichen enthalten. Inwieweit sich solcher Leerraum in eigenen Textknoten wiederfindet, wird von der XPath nutzenden Anwendung bestimmt. Schließlich sei auf die implizit zu jedem Element gehörenden Namensraumknoten für den xml-Namensraum hingewiesen.

Das Document Object Model [DOM] definiert ebenfalls eine Baumrepräsentation, die allerdings von der in XPath verwendeten in einigen Punkten abweicht. Auf diese Unterschiede wird innerhalb des Kapitels [5 Datenmodell] eingegangen.

Das primäre syntaktische Konstrukt in XPath ist der Ausdruck. Ein Ausdruck passt zu der Produktion Expr. Die Auswertung eines Ausdrucks ergibt ein Objekt, das zu einem der folgenden vier Grundtypen gehört:

Anmerkung des Übersetzers:

Das sind die vier Grundtypen, die XPath definiert. Tatsächlich können darauf aufbauende Spezifikationen weitere Typen definieren, sodass die Auswertung eines XPath-Ausdrucks ein Objekt dieses neuen Typs ergeben kann. Insbesondere können im Ausdruck enthaltene Variablen Objekte anderer Typen aufnehmen.

Wie man sieht, gibt es keinen Datentyp für Knoten. Ein einzelner Knoten kann aber als Knotenmenge (node-set) dargestellt werden, die genau ein Element enthält.

Die innerhalb von Zeichenketten erlaubten UCS-Zeichen (Universal Multiple-Octet Coded Character Set) sind in [ISO/IEC 10646] bzw. [ISO/IEC 10646, 2nd Edition] beschrieben.

Ein Ausdruck wird immer bezüglich eines Kontextes ausgewertet. XSLT und XPointer spezifizieren, wie dieser Kontext bei der Verwendung von XPath-Ausdrücken in XSLT beziehungsweise XPointer bestimmt wird. Der Kontext besteht aus:

Die Kontextposition ist immer kleiner oder gleich der Kontextgröße.

Die Variablenbelegungen bestehen aus einer Abbildung von Variablennamen auf Variablenwerte. Der Wert einer Variablen ist ein Objekt, welches von jedem beliebigen Typ sein kann, der für Ausdrücke möglich ist. Daneben sind auch weitere Typen möglich, die hier nicht spezifiziert werden.

Anmerkung des Übersetzers:

In der XSLT-1.0-Spezifikation [XSLT] wird beispielsweise als neuer Typ Ergebnisteilbaum (result tree fragment) eingeführt. Werte dieses Typs entstehen im Ergebnis des Transformationsprozesses. Durch die folgende Variablenvereinbarung wird z.B. eine Variable namens antwort erzeugt, deren Wert ein Ergebnisteilbaum ist:

<xsl:variable name="antwort">
   <antwort><xsl:value-of select="6 * 7" /></antwort>
</xsl:variable>

Dieser Typ wird voraussichtlich in zukünftigen XSLT-Versionen nicht mehr existieren, da das Ergebnis einer Transformation dann eine normale Knotenmenge vom Typ node-set ist, siehe [XSLT 1.1].

Die folgende Anweisung erzeugt dagegen eine Variable, deren Wert sich aus der Berechnung eines XPath-Ausdrucks expression ergibt:

<xsl:variable name="var" select="expression" />

An dieser Stelle sei darauf hingewiesen, dass die Erzeugung der Variablenbelegungen für antwort und var ein XSLT-Sprachmittel ist. XPath selbst stellt hierfür keinerlei Konstrukte bereit. Neben xsl:variable besitzt XSLT für diesen Zweck xsl:param.

Die XPointer-Spezifikation [XPointer], die ebenfalls XPath nutzt, sieht keine Möglichkeiten für das Erzeugen von Variablenbelegungen vor. Die Verwendung von Variablenreferenzen innerhalb eines XPointer-Ausdrucks führt daher zu einem syntaktischen Fehler. Die als Arbeitsentwurf des W3C vorgelegte Abfragesprache für XML-Dokumente XQuery [XQuery] benutzt zur Erzeugung von Variablenbelegungen sogenannte FLWR-Ausdrücke (gesprochen "flower", eine Abkürzung für FOR-, LET-, WHERE- und RETURN-Klauseln).

Andere auf XPath aufbauende Spezifikationen müssen in analoger Weise definieren, wie Variablenbelegungen für einen Kontext erzeugt werden.

Die Funktionsbibliothek besteht aus einer Abbildung von Funktionsnamen auf Funktionen. Jede Funktion besitzt null oder mehr Argumente und liefert einen einzelnen Wert. Diese Spezifikation definiert eine Bibliothek von Grundfunktionen, die von allen XPath-Implementationen unterstützt werden muss (siehe [4 Bibliothek der Grundfunktionen]). Bei einer Grundfunktion gehören die Argumente und das Ergebnis einem der vier Grundtypen an. Sowohl XSLT als auch XPointer erweitern XPath um zusätzliche Funktionen, von denen einige auf den vier Grundtypen, andere auf zusätzlichen, durch XSLT und XPointer definierten Typen operieren.

Namensraum-Deklarationen bestehen aus einer Abbildung von Präfixen auf Namespace-URIs.

Anmerkung des Übersetzers:

Angenommen, ein Element enthält in seinem Start-Tag folgende Namensraum-Deklaration: xmlns:xlink="http://www.w3.org/1999/xlink". Ein Kontext, für den diese Deklaration gültig ist, enthält dann eine Abbildung des Präfix xlink auf den URI http://www.w3.org/1999/xlink.

Die Variablenbelegungen, die Funktionsbibliothek und die Namensraum-Deklarationen, die benutzt werden, um einen Teilausdruck zu berechnen, sind immer dieselben, die auch für den umgebenden Ausdruck benutzt werden. Der Kontextknoten, die Kontextposition und die Kontextgröße, die zur Berechnung eines Teilausdrucks benutzt werden, sind dagegen zuweilen verschieden von denen des umgebenden Ausdrucks. Mehrere Arten von Ausdrücken ändern den Kontextknoten, aber nur Prädikate ändern die Kontextposition und die Kontextgröße (siehe [2.4 Prädikate]). Bei der Beschreibung, wie bestimmte Ausdrücke zu berechnen sind, wird immer explizit angegeben, ob sich der Kontextknoten, die Kontextposition oder die Kontextgröße bei der Berechnung von Teilausdrücken ändern. Wird nichts über Kontextknoten, Kontextposition und Kontextgröße ausgesagt, bleiben sie bei der Berechnung von Teilausdrücken dieser Ausdrücke gleich.

Anmerkung des Übersetzers:

Zur Erklärung hier ein kleiner Vorgriff:

Innerhalb eines Lokalisierungspfades ändert jeder Schritt den Kontextknoten, der für die Berechnung der folgenden Schritte relevant ist. Durch ein Prädikat werden Knoten aus einer Knotenmenge herausgefiltert, sodass die Kontextgröße sich in der Regel verkleinert und die Position der gefilterten Knoten sich entsprechend ändert.

XPath-Ausdrücke erscheinen häufig in XML-Attributen. Die in diesem Abschnitt spezifizierte Grammatik wird auf Attributwerte nach ihrer Normalisierung gemäß XML 1.0 angewendet. Wenn beispielsweise die Grammatik das Zeichen < verwendet, so darf dieses nicht in der XML-Quelle als < auftreten, sondern muss gemäß den XML-1.0-Regeln notiert werden, zum Beispiel durch Eingabe als &lt;. Innerhalb von Ausdrücken werden Zeichenkettenliterale durch einfache oder doppelte Anführungszeichen begrenzt, die ebenfalls zur Begrenzung von XML-Attributen verwendet werden. Um zu vermeiden, dass ein Anführungszeichen innerhalb eines Ausdrucks durch den XML-Prozessor als Abschluss des Attributwertes interpretiert wird, kann das Anführungszeichen als Zeichenreferenz eingegeben werden (&quot; oder &apos;). Alternativ können im Ausdruck einfache Anführungszeichen benutzt werden, falls das XML-Attribut durch doppelte Anführungszeichen begrenzt wird oder umgekehrt.

Anmerkung des Übersetzers:

Statt "Zeichenreferenz" muss es hier "Entity-Referenz" heißen.

Abgesehen davon gibt es immer noch Fälle, in denen dieses einfache Kochrezept nicht ausreichend ist - nämlich dann, wenn eine Zeichenkette benötigt wird, die beide Arten von Anführungszeichen enthalten soll.

Angenommen es soll getestet werden, ob der Inhalt des Elements para mit der Zeichenkette »Sie fragte: "Wie geht's?"« übereinstimmt. Möchte man diese Zeichenkette innerhalb eines XPath-Ausdrucks durch doppelte Anführungszeichen begrenzen, könnte man auf die Idee kommen, beispielsweise durch Verwendung der Entity-Referenz &quot; folgendes zu schreiben:

para="Sie fragte: &quot;Wie geht's?&quot;"

Das ist aber keine Lösung, da ein XML-Parser, der diese Zeichenfolge analysiert, Entity-Referenzen auflöst. Ein darauf aufsetzender XPath-Prozessor kann nicht mehr zwischen »"« und »&quot;« unterscheiden. Formuliert man im nächsten Schritt dann nämlich weiter

<xsl:if test='para="Sie fragte: &quot;Wie geht&apos;s?&quot;"'>

(diese Zeile ist im XML-Sinn wohlgeformt), so führt das zu einem Fehler im XPath-Prozessor, da dieser trotzdem die folgende Zeichenkette auswertet:

para="Sie fragte: "Wie geht's?""

Eine einfache Lösung für solche Fälle besteht darin, die betreffende Zeichenkette als Wert einer Variablen zu definieren, etwa in XSLT per

<xsl:variable name="string">Sie fragte: "Wie geht's?"</xsl:variable>

und anschließend diese Variable in XPath-Ausdrücken zu verwenden.

<xsl:if test="para=$string">

Alternativ kann man die gewünschte Zeichenkette aus mehreren Teilen zusammensetzen (unter Benutzung der noch zu erläuternden Funktion concat), wobei jede Teilzeichenkette jeweils nur eine Sorte von Anführungszeichen enthält:

para=concat('Sie fragte: "Wie geht', "'", 's?"')

Das Anführungszeichen, das zur Begrenzung dieses Ausdrucks innerhalb eines Attributwertes genutzt wird, muss dann durch die dazugehörige Entity-Referenz ersetzt werden. Das Ergebnis sieht zwar unübersichtlich aus, ist aber syntaktisch korrekt:

<xsl:if test="para=concat('Sie fragte: &quot;Wie geht',
                          &quot;'&quot;, 's?&quot;')">

Diese zweite Variante muss verwendet werden, wenn Variablen nicht erlaubt sind, etwa innerhalb eines XSLT-Musters oder als Bestandteil eines XPointers.

Ein wichtiger spezieller Ausdruck ist der Lokalisierungspfad. Ein Lokalisierungspfad wählt eine Knotenmenge relativ zu einem Kontextknoten aus. Das Ergebnis der Berechnung eines Ausdrucks, der ein Lokalisierungspfad ist, ist genau die Knotenmenge, die die durch den Lokalisierungspfad ausgewählten Knoten enthält. Lokalisierungspfade können rekursiv Ausdrücke enthalten, die zum Filtern von Knotenmengen benutzt werden. Ein Lokalisierungspfad passt auf die Produktion LocationPath.

Die in der nachfolgenden Grammatik verwendeten Nichtterminale QName und NCName sind in [XML Names] definiert, S ist in [XML] definiert. Die Grammatik verwendet die gleiche EBNF-Notation wie in [XML] (mit der Ausnahme, dass Grammatiksymbole immer mit einem Großbuchstaben beginnen).

Anmerkung des Übersetzers:

Die Erweiterte Backus-Naur-Form (EBNF) wird zur Notation von formalen Grammatiken verwendet. Sie wird in Kapitel Notation der XML-Spezifikation [XML, 2nd Edition] näher erläutert.

Ausdrücke werden geparst, indem die Zeichenfolge in einzelne Token zerlegt wird, und anschließend die entstehende Folge der Token geparst wird. Leerraumzeichen können beliebig zwischen Token verwendet werden. Der Zerlegungsprozess wird in [3.7 Lexikalische Struktur] beschrieben.

Anmerkung des Übersetzers:

Ein Token ist eine syntaktische Einheit von Zeichen, etwa der Name »html«, die Zahl »3.14159« oder der Operator »!=«. Die zwischen diesen Token erlaubten Leerraumzeichen sind gemäß der XML-Spezifikation Folgen aus Leerzeichen (#x20), Tabulatoren (#x9), Zeilenvorschüben (#xA) und Wagenrückläufen (#xD). Innerhalb eines Tokens dürfen keine solchen Leerraumzeichen auftreten, so z.B. nicht zwischen den beiden einzelnen Zeichen »!« und »=« des Operators »!=«.

2 Lokalisierungspfade

Obwohl Lokalisierungspfade nicht das allgemeinste grammatische Konstrukt der Sprache darstellen (ein Lokalisierungspfad ist ein Spezialfall eines Ausdrucks), sind sie doch das wichtigste Konstrukt und werden deshalb als erstes beschrieben.

Jeder Lokalisierungspfad kann durch eine unkomplizierte und eher verbale Syntax ausgedrückt werden. Daneben gibt es eine Reihe von syntaktischen Abkürzungen, mit denen sich häufige Fälle kurz und prägnant ausdrücken lassen. Dieser Abschnitt erläutert die Semantik von Lokalisierungspfaden anhand der ausführlichen Syntax. Die abgekürzte Syntax wird im Anschluss daran erläutert, indem gezeigt wird, wie diese auf die ausführliche Syntax abgebildet wird (siehe [2.5 Abgekürzte Syntax]).

Es folgen einige Beispiele für Lokalisierungspfade unter Benutzung der ausführlichen Syntax:

Es gibt zwei Arten Lokalisierungspfade: relative und absolute Lokalisierungspfade.

Ein relativer Lokalisierungspfad wird durch eine Folge aus einem oder mehreren Lokalisierungsschritten gebildet, die durch / voneinander getrennt sind. Die Schritte eines relativen Lokalisierungspfades werden von rechts nach links zusammengesetzt. Jeder Schritt wählt der Reihe nach eine Knotenmenge relativ zu einem Kontextknoten aus. Eine Anfangsfolge von Schritten wird mit einem folgenden Schritt wie folgt zusammengesetzt: Die Anfangsfolge von Schritten wählt eine Knotenmenge relativ zu einem Kontextknoten aus. Jeder Knoten in dieser Menge wird dann als Kontextknoten für den folgenden Schritt benutzt. Die durch diesen Schritt bestimmten Knotenmengen werden vereinigt. Die Vereinigung ist dann genau die Knotenmenge, die durch das Zusammensetzen der Schritte ausgewählt wird. Zum Beispiel wählt child::div/child::para die para-Kindelemente der div-Kindelemente des Kontextknotens aus, oder - mit anderen Worten - die para-Enkelelemente, die div-Elternelemente haben.

Ein absoluter Lokalisierungspfad besteht aus dem Zeichen / und einem optional folgenden relativen Lokalisierungspfad. Ein / allein wählt den Wurzelknoten des Dokuments aus, das den Kontextknoten enthält. Falls ein relativer Lokalisierungspfad folgt, so wählt der Lokalisierungspfad die Knotenmenge aus, die ein relativer Lokalisierungspfad relativ zum Wurzelknoten des den Kontextknoten enthaltenen Dokuments auswählen würde.

Anmerkung des Übersetzers:

Hier bietet sich der Vergleich zu Pfaden im Dateisystem an: Sowohl in UNIX-Betriebssystemen als auch innerhalb von URLs wird der Schrägstrich »/« als Trennzeichen innerhalb von Dateipfaden benutzt. In ähnlicher Weise kann man sich Pfade in einem XML-Baum vorstellen. Ein relativer Pfad geht immer vom aktuellen Knoten (dem Kontextknoten) aus, ein absoluter Pfad beginnt immer an der Dokumentwurzel. Genaugenommen ist ein absoluter Pfad allerdings ebenfalls relativ, nämlich zum Dokument des Kontextknotens. Das spielt eine Rolle, wenn Knoten aus mehreren Dokumenten verarbeitet werden.

Man sollte sich allerdings einer Feinheit bewusst sein: während beispielsweise durch »verzeichnis1/verzeichnis2/datei3« in einem Dateisystem exakt eine Datei adressiert wird, eben jene, die den Namen »datei3« trägt und sich in dem Unterverzeichnis »verzeichnis1/verzeichnis2« befindet, wählt ein analoger XPath immer eine Knotenmenge aus, die in der Regel mehrere Knoten enthalten kann. Das sollte aber nicht weiter verwundern, darf ein Element doch durchaus mehrere gleichnamige Kindelemente besitzen.

Lokalisierungspfade
[1]    LocationPath    ::=    RelativeLocationPath
| AbsoluteLocationPath
[2]    AbsoluteLocationPath    ::=    '/' RelativeLocationPath?
| AbbreviatedAbsoluteLocationPath
[3]    RelativeLocationPath    ::=    Step
| RelativeLocationPath '/' Step
| AbbreviatedRelativeLocationPath

Anmerkung des Übersetzers:

Die obige Grammatik gibt das bisher Beschriebene noch einmal formal wieder. Wie man sieht, können Lokalisierungspfade auch abgekürzte Bestandteile enthalten. Diese werden in Kapitel [2.5 Abgekürzte Syntax] beschrieben.

2.1 Lokalisierungsschritte

Ein Lokalisierungsschritt hat drei Bestandteile:

Ein Lokalisierungsschritt besteht syntaktisch aus dem Namen der Achse, gefolgt von zwei Doppelpunkten und dem Knotentest, gefolgt von null oder mehr in eckigen Klammern eingeschlossenen Ausdrücken. Zum Beispiel enthält child::para[position()=1] die Achse child, den Knotentest para und ein Prädikat [position()=1].

Die durch den Lokalisierungspfad ausgewählte Knotenmenge ergibt sich aus der durch Achse und Knotentest bestimmten Ausgangsknotenmenge, indem dort der Reihe nach die einzelnen Prädikate angewendet werden.

Die Ausgangsknotenmenge enthält alle Knoten, die zum Kontextknoten in der durch die Achse angegebenen Beziehung stehen, und den im Knotentest spezifizierten Knotentyp und erweiterten Namen besitzen. Zum Beispiel wählt der Lokalisierungsschritt descendant::para alle para-Nachkommen des Kontextknotens aus: descendant besagt, dass jeder Knoten in der Ausgangsknotenmenge ein Nachkomme des Kontextknotens sein muss; para besagt, dass jeder Knoten in der Ausgangsknotenmenge ein Element mit dem Namen para sein muss. Die verfügbaren Achsen werden in [2.2 Achsen] beschrieben, die verfügbaren Knotentests in [2.3 Knotentests]. Die Bedeutung einiger Knotentests hängt von der jeweiligen Achse ab.

Die Ausgangsknotenmenge wird durch das erste Prädikat gefiltert und ergibt eine neue Knotenmenge. Diese wird anschließend durch das zweite Prädikat gefiltert und so weiter. Die resultierende Knotenmenge ist schließlich die Knotenmenge, die durch den Lokalisierungsschritt ausgewählt wird. Die Achse beeinflusst, wie der Ausdruck in jedem Prädikat berechnet wird. Die Semantik eines Prädikats ist damit bezüglich einer Achse definiert. Siehe [2.4 Prädikate].

Anmerkung des Übersetzers:

Dieser letzte Satz bezieht sich auf Prädikate, die die Kontextposition und damit die Näheposition der gefilterten Knoten auswerten.

Zur Verdeutlichung der Vorgehensweise bei mehreren Prädikaten sei auf die beiden bereits diskutierten Beispiele

child::para[attribute::type="warning"][position()=5]

und

child::para[position()=5][attribute::type="warning"]

in Kapitel [2 Lokalisierungspfade] verwiesen.

Lokalisierungsschritte
[4]    Step    ::=    AxisSpecifier NodeTest Predicate*
| AbbreviatedStep
[5]    AxisSpecifier    ::=    AxisName '::'
| AbbreviatedAxisSpecifier

2.2 Achsen

Es stehen die folgenden Achsen zur Verfügung:

Anmerkung: Die Achsen ancestor, descendant, following, preceding und self partitionieren ein Dokument (unter Auslassung der Attribut- und Namensraum-Knoten): sie überschneiden sich nicht und enthalten zusammen alle Knoten des Dokuments.

Anmerkung des Übersetzers:

Achsen-Aufteilung eines Dokuments
Achsen
[6]    AxisName    ::=    'ancestor'
| 'ancestor-or-self'
| 'attribute'
| 'child'
| 'descendant'
| 'descendant-or-self'
| 'following'
| 'following-sibling'
| 'namespace'
| 'parent'
| 'preceding'
| 'preceding-sibling'
| 'self'

Anmerkung des Übersetzers:

Attribut- und Namensraum-Achse nehmen hier eine Sonderrolle ein. Die adressierten Knoten zeichnen sich nämlich durch einen bestimmten festen Knotentyp aus (den sogenannten Hauptknotentyp). Da diese Knoten per Definition keine Kinder anderer Knoten sind, wurden die speziellen Achsen attribute und namespace definiert. Trotzdem kann sich auch an diese Achsen ein beliebiger Knotentest anschließen (siehe [2.3 Knotentests]). Dies birgt die Gefahr, dass zwar syntaktisch korrekte aber sinnlose Lokalisierungsschritte benutzt werden können, die niemals einen Knoten auswählen. Der Lokalisierungsschritt attribute::text(), der über die Attributachse einen Textknoten auswählen soll, liefert beispielsweise immer eine leere Knotenmenge.

2.3 Knotentests

Jede Achse besitzt einen Hauptknotentyp. Falls eine Achse Elemente enthalten kann, so ist der Hauptknotentyp der Elementtyp, ansonsten ist es genau der Typ der Knoten, die die Achse enthalten kann. Das bedeutet,

Ein Knotentest, der ein QName ist, ist genau dann erfüllt, wenn der Knotentyp (siehe [5 Datenmodell]) der Hauptknotentyp ist und einen erweiterten Namen besitzt, der gleich dem erweiterten Namen des QName ist. Beispielsweise wählt child::para die para-Kindelemente des Kontextknotens aus. Falls der Kontextknoten keine para-Kinder besitzt, ist das Ergebnis eine leere Knotenmenge. attribute::href wählt die href-Attribute des Kontextknotens aus. Falls der Kontextknoten keine href-Attribute besitzt, ist das Ergebnis eine leere Knotenmenge.

Anmerkung des Übersetzers:

Das Akronym QName steht für "qualifizierter Name" und bedeutet, dass der entsprechende Name aus einem optionalen Präfix und einem lokalen Bestandteil bestehen kann. Beide Teile werden durch einen Doppelpunkt voneinander getrennt. Durch das Präfix wird der Namensraum bestimmt, zu dem der lokale Name gehört. Im Beispiel xlink:href ist xlink das Präfix und href der lokale Bestandteil. Die obigen Beispiele verwenden Knotentests, die letztendlich nur lokale Namen sind, also keine Namensräume berücksichtigen.

Möchte man auf das href-Attribut aus dem xlink-Namensraum zugreifen, wäre also zu schreiben: attribute::xlink:href. Entsprechend greift man per preceding-sibling::xhtml:h1 auf die dem Kontextknoten vorhergehenden h1-Elemente aus dem xhtml-Namensraum zu. Schließlich ein Beispiel für die Namensraum-Achse: namespace::xlink wählt genau den Namensraum-Knoten aus, der zum Präfix xlink gehört. Der qualifierte Name eines Namensraum-Knotens enthält übrigens niemals ein Präfix, siehe [5.4 Namensraum-Knoten].

Wie in den Beispielen am Beginn des Kapitels bereits gezeigt wurde, eignet sich die Achse self, um innerhalb eines Prädikats bestimmte Elementtypen aus einer Knotenmenge herauszufiltern, wie z.B. in child::*[self::chapter or self::appendix]. Leider funktioniert eine analoge Vorgehensweise für Attribut- oder Namensraum-Knoten nicht. Das erweist sich insbesondere bei negativen Bedingungen als hinderlich. Möchte man z.B. alle Attribute bis auf das href-Attribut auswählen, leistet attribute::*[not(self::href)] leider nicht das Gewünschte. Dieser Ausdruck liefert nämlich nach wie vor alle Attribute. Da die self-Achse Elemente enthalten kann, ihr Hauptknotentyp somit der Elementtyp ist, sucht der Ausdruck self::href immer nach einem Element mit dem Namen href, niemals nach einem Attribut. Eine Lösung für dieses Problem besteht in der Auswertung des Attributnamens, siehe die Funktionen name und local-name.

Ein QName im Knotentest wird in einen erweiterten Namen unter Verwendung der Namensraum-Deklarationen aus dem Kontext des Ausdrucks expandiert. Dies geschieht in der gleichen Weise wie bei Elementnamen in Start- und End-Tags, allerdings mit der Ausnahme, dass ein mit xmlns deklarierter voreingestellter Namensraum nicht genutzt wird: d.h. enthält QName kein Präfix, so ist der Namensraum-URI leer (das ist die gleiche Regel, nach der auch Attributnamen expandiert werden). Es ist ein Fehler, wenn der QName ein Präfix enthält, für den es keine Namensraum-Deklaration im Kontext des Ausdrucks gibt.

Anmerkung des Übersetzers:

Qualifizierte Namen werden also gemäß der Namensraum-Empfehlung [XML Names] expandiert. Das bedeutet insbesondere, dass in einem XPath-Ausdruck nicht das gleiche Präfix wie im betrachteten XML-Dokument benutzt werden muss. Wichtig ist nur, dass beide Präfixe den gleichen Namensraum repräsentieren. Wenn beispielsweise das zugrundeliegende XML-Dokument ein XHTML-Dokument ist, dessen Elemente zum Namensraum http://www.w3.org/1999/xhtml gehören, so kann beispielsweise das Dokument-Element über den XPath-Ausdruck /child::xhtml:html ausgewählt werden - vorausgesetzt, das Präfix xhtml wurde im Kontext des Ausdrucks an den gleichen Namensraum gebunden. Dabei ist es völlig unerheblich, welches Präfix im XHTML-Dokument benutzt wurde - es ist sogar möglich, dass dort nur eine Deklaration für den voreingestellten Namensraum vorkommt: <html xmlns="http://www.w3.org/1999/xhtml">

Gerade in diesen Fällen ist Vorsicht geboten. Sehr leicht übersieht man eine solche Namensraumdeklaration, die sich selbstverständlich auch auf alle Kindelemente auswirkt, und ist gewillt, nur den jeweiligen Elementnamen in einem Ausdruck anzugeben, z.B. bei folgender XSLT-Anweisung: <xsl:value-of select="title" />. Richtig wäre stattdessen (der Vollständigkeit halber mit Namensraum-Deklaration): <xsl:value-of select="xhtml:title" xmlns:xhtml="http://www.w3.org/1999/xhtml"> Entsprechend müssen in Lokalisierungpfaden alle Schritte vollständig qualifiziert sein: xhtml:div/xhtml:p.

Stellt man fest, dass XPath-Ausdrücke nach dem Einfügen einer DTD in das Originaldokument nicht mehr die richtigen Knoten zurückliefern (was sich beispielsweise darin äußert, dass ein XSLT-Stylesheet nicht mehr die erwartete Ausgabe liefert), ist in der Regel ebenfalls die Deklaration eines voreingestellten Namensraums die Ursache. Eine Deklaration innerhalb der DTD der Form <!ATTLIST html xmlns CDATA #FIXED "http://www.w3.org/1999/xhtml"> versetzt alle Kindelemente von html ohne Präfix und auch html selbst in den XHTML-Namensraum. Ohne die DTD gehören sie keinem Namensraum an. In solchen Fällen sollte man die Deklaration des voreingestellten Namensraums in das XML-Dokument aufnehmen, damit XPath-Ausdrücke unabhängig von der Auswertung einer DTD immer das gleiche Ergebnis liefern.

Schließlich sei noch einmal darauf hingewiesen, dass sich ein voreingestellter Namensraum im Kontext eines XPath-Ausdrucks nicht auf den Ausdruck auswirkt. Ein qualifizierter Name ohne Präfix adressiert damit immer ein Element oder ein Attribut, das zu keinem Namensraum gehört. Die folgende Variante ist damit keine Alternative zum obigen Beispiel: <xsl:value-of select="title" xmlns="http://www.w3.org/1999/xhtml">

Ein Knotentest * ist für jeden Knoten des Hauptknotentyps erfüllt. Beispielsweise wählt child::* alle Kindelemente und attribute::* alle Attributknoten des Kontextknotens aus.

Anmerkung des Übersetzers:

Handelt es sich beim Kontextknoten um einen Elementknoten, so liefert der Schritt parent::* nur dann die leere Knotenmenge, wenn dieser das Dokument-Element repräsentiert. Der Elementknoten für das Dokument-Element besitzt zwar ebenfalls einen Elternknoten, nämlich die Wurzel /, diese ist aber nicht vom Hauptknotentyp der Achse parent, dem Elementtyp.

Ein Knotentest kann in der Form NCName:* auftreten. In diesem Fall wird das Präfix wie bei einem QName unter Verwendung der Namensraum-Deklarationen des Kontextes expandiert. Es ist ein Fehler, wenn es für das Präfix keine Namensraum-Deklaration im Kontext des Ausdrucks gibt. Der Knotentest ist erfüllt für jeden Knoten des Hauptknotentyps, dessen erweiterter Name den Namensraum-URI besitzt, zu dem das Präfix expandiert, unabhängig vom lokalen Bestandteil des Namens.

Anmerkung des Übersetzers:

Beispielsweise wählen descendant::xhtml:* alle Nachkommen aus dem xhtml-Namensraum und attribute::xlink:* alle Attribute aus dem xlink-Namensraum aus.

Diese Form von Knotentests kann in einem XSLT-Stylesheet innerhalb eines Musters z.B. dazu genutzt werden, alle Elemente eines bestimmten Namensraums in der gleichen Weise zu behandeln. Eingebettete XHTML-Elemente in einem beliebigen zu transformierenden XML-Dokument können auf diese Weise einfach in die Ausgabe kopiert werden, ohne dass diese Elemente explizit benannt werden müssen.

Der Knotentest text() ist erfüllt für jeden Textknoten. Zum Beispiel wählt child::text() alle Textknoten, die Kinder des Kontextknotens sind, aus. Analog ist der Knotentest comment() erfüllt für jeden Kommentarknoten und der Knotentest processing-instruction() erfüllt für jede Processing Instruction. Dem Test processing-instruction() kann ein Literal als Argument übergeben werden. In diesem Fall ist der Test für jede Processing Instruction erfüllt, deren Name gleich dem Wert des übergebenen Literals ist.

Anmerkung des Übersetzers:

Offensichtlich werden Kommentare nicht einfach ignoriert, sondern durch eigene Knoten innerhalb des XML-Baumes repräsentiert. Auf diese Weise können XPath-Ausdrücke mittels comment() auch auf Kommentarknoten zugreifen. Ein Stylesheet kann damit XML-Kommentare verarbeiten und diese geeignet darstellen.

Für Processing Instructions gibt es ebenfalls entsprechende Knoten im XML-Baum. Jede Processing Instruction besitzt einen Namen (ein Ziel), z.B. xml-stylesheet in <?xml-stylesheet href=... ?>. Wird dieser Name im Knotentest processing-instruction() angegeben, ist der entsprechende Test nur für Processing Instructions mit gleichem Namen erfüllt. Namen von Processing Instructions werden dabei nicht von Namensraumdeklarationen beeinflusst. Das Argument für processing-instruction() ist damit kein qualifizierter Name, sondern ein Zeichenkettenliteral. Der Knotentest für die zitierte Processing Instruction lautet z.B. processing-instruction('xml-stylesheet').

Der Knotentest node() ist für alle Knoten jedes beliebigen Typs erfüllt.

Anmerkung des Übersetzers:

Möchte man alle Knoten eines Dokumentes auswählen, kann man z.B. die folgenden Knotenmengen vereinigen: /descendant-or-self::node(), /descendant-or-self::node()/attribute::* und /descendant-or-self::node()/namespace::*.

Es wurde bereits auf die Sonderrolle von Attribut- und Namensraum-Knoten hingewiesen. Diese werden nicht durch einen Knotentest, sondern durch entsprechende Achsen ausgewählt. Das hat zur Folge, dass sich zwar einfach prüfen lässt, ob der Kontextknoten z.B. ein Textknoten ist (per self::text(); analog für Element- Kommentar- und Processing-Instruction-Knoten), allerdings funktioniert diese Methode nicht bei Attribut- und Namensraum-Knoten. Hier muss man stattdessen überprüfen, ob sich der Kontextknoten in der Menge der Attribut- bzw. Namensraum-Knoten des Elternknotens befindet, siehe [3.3 Knotenmengen].

[7]    NodeTest    ::=    NameTest
| NodeType '(' ')'
| 'processing-instruction' '(' Literal ')'

2.4 Prädikate

Eine Achse ist entweder vorwärts- oder rückwärtsgerichtet. Eine vorwärtsgerichtete Achse enthält immer nur den Kontextknoten oder Knoten, die nach dem Kontextknoten im Dokument auftreten. Eine rückwärtsgerichtete Achse enthält immer nur den Kontextknoten oder Knoten, die vor dem Kontextknoten im Dokument auftreten. Demzufolge sind die Achsen ancestor, ancestor-or-self, preceding und preceding-sibling rückwärtsgerichtete Achsen. Alle anderen Achsen sind vorwärtsgerichtet. Da die Achse self immer höchstens einen Knoten enthält, hat es keine Bedeutung, ob sie als vorwärts- oder rückwärtsgerichtete Achse betrachtet wird. Die Näheposition eines Knotens in einer Knotenmenge bezüglich einer Achse ist definiert als die Position des Knotens in dieser Knotenmenge, welche in Dokumentordnung geordnet ist, wenn es sich um eine vorwärtsgerichtete Achse handelt, und welche in umgekehrter Dokumentordnung geordnet ist, wenn es sich um eine rückwärtsgerichtete Achse handelt. Die erste Position ist 1.

Anmerkung des Übersetzers:

Diese recht komplizierte Definition bedarf einer Erläuterung. Die Knoten in einer Knotenmenge sind ungeordnet - es handelt sich schließlich um eine Menge. Allerdings kann über die Funktion position die Position eines Knotens in der aktuellen Knotenliste bestimmt werden. Die Reihenfolge der Knoten orientiert sich an der Reihenfolge, in der die Knoten im XML-Dokument auftreten. Bei vorwärtsgerichteten Achsen wird diese Ursprungsreihenfolge beibehalten und man spricht von Dokumentordnung. Für rückwärtsgerichtete Achsen wird die Reihenfolge umgekehrt, und man spricht von umgekehrter Dokumentordnung.

Die obige Definition hat zur Folge, dass innerhalb eines Lokalisierungsschrittes immer der nächstgelegene Knoten die Position 1 hat. Abhängig von der Blickrichtung kann es sich um einen unmittelbaren Vorgänger (preceding) bzw. Vorfahren (ancestor) oder aber um einen unmittelbaren Nachfolger (following) bzw. Nachkommen (descendant) handeln. Der Begriff Näheposition beschreibt damit die Nähe zum Kontextknoten. Die Abbildungen zu den verschiedenen Achsen in Kapitel [2.2 Achsen] verdeutlichen die Näheposition der jeweiligen zur Achse gehörenden Knoten. Genaugenommen ist die parent-Achse ebenfalls rückwärtsgerichtet, allerdings enthält diese wie self maximal einen Knoten.

Die Näheposition ist nur innerhalb von Prädikaten in Lokalisierungsschritten von Bedeutung, da hier die ausschlaggebende Achse bekannt ist. Die in [4.2 Zeichenkettenfunktionen] vorgestellte Funktion string (ebenso wie die Funktionen number und boolean) konvertiert dagegen bei einer Knotenmenge immer den ersten Knoten bezüglich der Dokumentordnung, unabhängig davon, auf welchem Weg diese Knotenmenge gebildet wurde.

Für vorwärtsgerichtete Achsen gilt daher folgende Gleichheit (am Beispiel following):

string(following::p) = string(following::p[position()=1])

Dies ist bei rückwärtsgerichteten Achsen nicht der Fall. Stattdessen gilt hier (am Beispiel preceding):

string(preceding::p) = string(preceding::p[position()=last()])

Die XSLT-Anweisung xsl:value-of verwendet implizit die Funktion string, um einen Textknoten zu generieren. Will man also auf den Wert des ersten Knotens einer rückwärtsgerichteten Achse zugreifen, muss man diesen immer explizit durch ein Prädikat auswählen. Die Ausgabe des Wertes eines Attributs id des Vorgängerknotens erfolgt daher z.B. durch: <xsl:value-of select="preceding::p[position()=1]/@id" />

Für Attribute und Namensraum-Knoten ist die Diskussion um Position und Richtung bedeutungslos. Das liegt daran, dass die Reihenfolge, in der Attribute und Namensraum-Deklarationen im Start-Tag eines Elementes angegeben wurden, als irrelevant angesehen wird. Informationen darüber sind daher nicht mehr im XML-Baum enthalten.

Ein Prädikat filtert eine Knotenmenge bezüglich einer Achse und produziert damit eine neue Knotenmenge. Für jeden zu filternden Knoten der Knotenmenge wird der dazugehörige Ausdruck PredicateExpr berechnet, und zwar mit diesem Knoten als Kontextknoten, der Anzahl der Knoten der Knotenmenge als Kontextgröße und mit der Näheposition des Knotens in der Knotenmenge bezüglich der Achse als Kontextposition. Falls die Berechnung von PredicateExpr für diesen Knoten wahr ergibt, wird der Knoten in die Ergebnisknotenmenge aufgenommen, andernfalls nicht.

Anmerkung des Übersetzers:

Diese Definition soll anhand eines Beispiels veranschaulicht werden:

ancestor::person[position() >= 2]

Achse und Knotentest ancestor::person liefern die Menge aller person-Elemente, die Vorfahren des Kontextknotens sind. Für jeden dieser Elementknoten wird nun der Ausdruck position() >= 2 berechnet. Die Kontextgröße ist dabei die Anzahl aller person-Vorfahren. Da ancestor eine rückwärtsgerichtete Achse ist, werden die Knoten entgegen der Originalreihenfolge nummeriert. Damit werden alle person-Elementknoten bis auf den ersten (d.h. den nächsten) in die Ergebnisknotenmenge aufgenommen. Da als Knotentest des Lokalisierungsschrittes person verwendet wurde (und nicht *) muss es sich bei diesem ersten person-Elementknoten nicht um den Elternknoten handeln. Würde sich ein weiteres Prädikat an den obigen Ausdruck anschließen, wäre die gerade berechnete Ergebnisknotenmenge Ausgangspunkt für dieses Prädikat.

Falls der Ausdruck eines nachfolgenden Prädikats nicht auf Kontextgröße oder -position zugreift, kann dieser Ausdruck bereits im ersten Prädikat berechnet und über den logischen Operator and mit dem dortigen Ausdruck verbunden werden. Der Lokalisierungsschritt

child::chapter[child::title][attribute::type="warning"]

liefert damit die gleiche Knotenmenge wie

child::chapter[child::title and attribute::type="warning"]

Ein PredicateExpr wird durch Berechnung des Expr und anschließender Konvertierung des Ergebnisses in einen booleschen Wert bestimmt. Falls das Ergebnis eine Zahl war, wird es für den Fall, dass diese Zahl gleich der Kontextposition ist, in den Wert wahr konvertiert, ansonsten in den Wert falsch. Wenn das Ergebnis keine Zahl war, dann wird es so konvertiert wie bei einem Aufruf der Funktion boolean. Damit ist ein Lokalisierungspfad para[3] äquivalent zu para[position()=3].

Anmerkung des Übersetzers:

Da die abgekürzte Syntax erst im folgenden Kapitel beschrieben wird, sollte als Beispiel hier besser child::para[3] verwendet werden.

Für Zahlen als Wert eines PredicateExpr gilt hier eine Sonderregel. Diese ermöglicht eine Schreibweise, die dem Zugriff auf Feldelemente in anderen Programmiersprachen gleicht. Allerdings muss beachtet werden, dass ein Ausdruck child::para[$num] nur dann gleichbedeutend mit child::para[position()=$num] ist, wenn die Variable num tatsächlich eine Zahl, also ein Objekt vom Typ number enthält. Wenn sie stattdessen nur eine geeignete Zeichenkette enthält, wird der Variableninhalt gemäß der Funktion boolean in einen booleschen Wert konvertiert. Das gleiche gilt für jedes andere Objekt, das sich in eine Zahl konvertieren ließe.

Prädikate
[8]    Predicate    ::=    '[' PredicateExpr ']'
[9]    PredicateExpr    ::=    Expr

2.5 Abgekürzte Syntax

Zunächst einige Beispiel für Lokalisierungspfade, die die abgekürzte Syntax benutzen:

Die wichtigste Abkürzung besteht darin, dass child:: in einem Lokalisierungsschritt weggelassen werden kann. Die Standard-Achse ist also child. So steht beispielsweise ein Lokalisierungspfad div/para abkürzend für child::div/child::para.

Für Attribute gibt es ebenfalls eine Abkürzung: attribute:: kann zu @ abgekürzt werden. Ein Lokalisierungspfad para[@type="warning"] steht beispielsweise abkürzend für child::para[attribute::type="warning"] und wählt damit para-Kindelemente mit einem Attribut type aus, dessen Wert gleich warning ist.

// ist die Abkürzung für /descendant-or-self::node()/. Zum Beispiel steht //para abkürzend für /descendant-or-self::node()/child::para und wählt damit alle para-Elemente im Dokument aus (selbst ein para-Element, das ein Dokument-Element ist, wird durch //para ausgewählt, da der Dokument-Elementknoten ein Kind des Wurzelknotens ist). div//para steht abkürzend für div/descendant-or-self::node()/child::para und wählt daher alle para-Nachfolger von div-Kindern aus.

Anmerkung des Übersetzers:

Hier enthält das Originaldokument einen kleinen Fehler. Der vollständige Lokalisierungspfad für das letzte Beispiel muss child::div/descendant-or-self::node()/child::para lauten.

Anmerkung: Der Lokalisierungspfad //para[1] bedeutet nicht das Gleiche wie /descendant::para[1]. Der zweite wählt das erste Nachkommen-Element para aus, der erste wählt alle para-Nachkommen aus, die das erste Kind ihrer Eltern sind.

Anmerkung des Übersetzers:

Davon kann man sich durch Bestimmung des vollständigen Ausdrucks leicht überzeugen:

//para[1] = /descendant-or-self::node()/para[1]
          = /descendant-or-self::node()/child::para[1]

Das Prädikat [1] wirkt damit auf die durch die child-Achse im zweiten Lokalisierungsschritt bestimmte Knotenmenge, wogegen es in /descendant::para[1] zur descendant-Achse gehört.

Ein Lokalisierungsschritt . steht abkürzend für self::node(). Das ist insbesondere in Verbindung mit // nützlich. Der Lokalisierungspfad .//para steht zum Beispiel abkürzend für

self::node()/descendant-or-self::node()/child::para

und wählt daher alle para-Elemente aus, die Nachkommen des Kontextknotens sind.

Analog steht der Lokalisierungsschritt .. abkürzend für parent::node(). Zum Beispiel steht ../title abkürzend für parent::node()/child::title und wählt damit die title-Kindelemente des Elternknotens des Kontextknotens aus.

Anmerkung des Übersetzers:

Die Kombination aus . und / ist unnötig und kann weggelassen werden. Ausdrücke der Form ./title oder ./@name können kürzer als title beziehungsweise @name geschrieben werden.

Ein Blick in die unten stehende Grammatik zeigt, dass es sich bei . und .. um vollständige Lokalisierungsschritte handelt. Ihnen können also keine Prädikate folgen. Ausdrücke der Form .[self::par] oder ..[@name='foo'] sind nicht zulässig.

Abkürzungen
[10]    AbbreviatedAbsoluteLocationPath    ::=    '//' RelativeLocationPath
[11]    AbbreviatedRelativeLocationPath    ::=    RelativeLocationPath '//' Step
[12]    AbbreviatedStep    ::=    '.'
| '..'
[13]    AbbreviatedAxisSpecifier    ::=    '@'?

3 Ausdrücke

3.1 Grundlagen

Eine Variablenreferenz (VariableReference) ergibt den Wert, der an den Variablennamen innerhalb der Menge der Variablenbelegungen des Kontexts gebunden ist. Es ist ein Fehler, falls dem Variablennamen in der Menge der Variablenbelegungen aus dem Kontext des Ausdrucks kein Wert zugewiesen wurde.

Anmerkung des Übersetzers:

Der Name einer Variablen ist ein qualifizierter Name, kann also ein Präfix enthalten, das auf einen Namensraum verweist. Mittels des Zeichens $ wird auf den Wert einer Variablen zugegriffen.

Der letzte Satz des obigen Abschnitts bedeutet, dass Variablen vor ihrer Benutzung definiert worden sein müssen. Wie bereits erwähnt, sieht XPath dafür keinerlei Sprachelemente vor. In [XSLT] verwendete Variablen haben immer einen definierten Wert. So wird durch das leere Element <xsl:variable name="foo:var" /> eine Variable namens foo:var definiert und mit der leeren Zeichenkette belegt.

Zum Gruppieren können runde Klammern verwendet werden.

[14]    Expr    ::=    OrExpr
[15]    PrimaryExpr    ::=    VariableReference
| '(' Expr ')'
| Literal
| Number
| FunctionCall

3.2 Funktionsaufrufe

Ein Ausdruck, der ein Funktionsaufruf (FunctionCall) ist, wird ausgewertet, indem anhand des Funktionsnamens (FunctionName) die Funktion in der Funktionsbibliothek des Ausdruckskontexts bestimmt wird, jedes der Argumente (Argument) berechnet und in den von der Funktion erwarteten Typ konvertiert wird, und schließlich die Funktion mit den konvertierten Argumenten aufgerufen wird. Es ist ein Fehler, wenn eine falsche Anzahl von Argumenten übergeben wird oder eines der Argumente nicht in den geforderten Typ konvertiert werden kann. Das Ergebnis des Funktionsaufrufes (FunctionCall) ist der von der Funktion zurückgelieferte Wert.

Die Konvertierung eines Arguments in den Typ string geschieht so wie bei beim Aufruf der der Funktion string. Die Konvertierung eines Arguments in den Typ number geschieht so wie bei beim Aufruf der der Funktion number. Die Konvertierung eines Arguments in den Typ boolean geschieht so wie bei beim Aufruf der der Funktion boolean. Ein Argument, das nicht vom Typ node-set ist, kann nicht in eine Knotenmenge konvertiert werden.

Anmerkung des Übersetzers:

Dieser letzte Satz stimmt insofern, als es keine automatische Konvertierung in eine Knotenmenge gibt. Zusätzliche Funktionen können durchaus Werte anderer Typen als Parameter entgegennehmen und eine Knotenmenge zurückliefern. In vielen XSLT-1.0-konformen Prozessoren existiert beispielsweise eine Erweiterungs-Funktion node-set, die für einen Ergebnisteilbaum dessen äquivalente Knotenmenge zurückliefert.

[16]    FunctionCall    ::=    FunctionName '(' ( Argument ( ',' Argument )* )? ')'
[17]    Argument    ::=    Expr

3.3 Knotenmengen

Ein Lokalisierungspfad kann als Ausdruck benutzt werden. Ein solcher Ausdruck liefert die durch den Pfad ausgewählte Knotenmenge.

Der Operator | berechnet die Vereinigung seiner Operanden, welche jeweils Knotenmengen sein müssen.

Anmerkung des Übersetzers:

Da es sich um eine Vereinigung von Mengen handelt, ist ein identischer Knoten in beiden Operanden in der Ergebnisknotenmenge auch nur einmal vorhanden. Zusammen mit der Funktion count (siehe [4.1 Funktionen auf Knotenmengen]) lässt sich so die Identität zweier Knoten feststellen.

Die Knotenmenge $a ist in der Knotenmenge $b enthalten, falls count($b) = count($a | $b). $a und $b sind identisch, wenn $a in $b und $b in $a enthalten ist. Es handelt sich um einzelne Knoten, wenn außerdem count($a) = 1 ist. Achtung: der Operator = bestimmt die Gleichheit der Zeichenkettenwerte zweier Knoten (siehe [3.4 Boolesche Werte]), nicht deren Identität.

XPath definiert keine Operatoren für die Bestimmung von Durchschnitt und Differenz zweier Knotenmengen. Basierend auf dem Teilmengentest lassen sich diese Operationen allerdings berechnen:

Durchschnitt von $a und $b:

$a[count(.|$b) = count($b)]

Differenz von $a und $b:

$a[count(.|$b) != count($b)]

Damit lässt sich nun auch testen, ob der Kontextknoten ein Attributknoten ist (analog für Namensraum-Knoten):

count(.|../@*) = count(../@*)

Die bedingte Auswahl einer Knotenmenge aus zwei Alternativen abhängig von einem logischen Ausdruck kann durch folgende Konstruktion erreicht werden:

node-set1[boolean-test] | node-set2[not(boolean-test)]

In den Programmiersprachen C(++) und Java stellt diese Funktionalität der Fragezeichenoperator ?: bereit. Eine analoge Anwendung für Zeichenketten wird im Zusammenhang mit der Funktion substring in Kapitel [4.2 Zeichenkettenfunktionen] vorgestellt.

In XSLT-Mustern, die eine Teilmenge der XPath-Ausdrücke bilden, wird der Operator | verwendet, um mögliche Alternativen anzugeben.

Prädikate werden zum Filtern von Ausdrücken in der gleichen Weise wie in Lokalisierungspfaden benutzt. Es ist ein Fehler, falls das Ergebnis des zu filternden Ausdrucks keine Knotenmenge ist. Das Prädikat filtert die Knotenmenge bezüglich der Kindachse.

Anmerkung: Die Bedeutung eines Prädikats hängt entscheidend davon ab, welche Achse angewendet wird. Zum Beispiel liefert preceding::foo[1] das erste foo-Element in umgekehrter Dokumentordnung, weil die für das Prädikat [1] anzuwendende Achse die Vorgängerachse (preceding) ist. Demgegenüber liefert (preceding::foo)[1] das erste foo-Element in Dokumentordnung, weil die Achse, die in diesem Fall für das Prädikat [1] gilt, die Kindachse ist.

Anmerkung des Übersetzers:

Auf diesen Unterschied soll noch einmal deutlich hingewiesen werden: Prädikate, die Bestandteil eines Lokalisierungsschrittes sind, filtern eine Knotenmenge bezüglich der im Lokalisierungsschritt verwendeten Achse. Für jeden Knoten der Knotenmenge ist daher dessen Näheposition relevant. Prädikate, die auf einen XPath-Ausdruck angewendet werden, interpretieren die betreffenden Knoten immer in Dokumentordnung, da laut Definition in so einem Fall die Kindachse anzuwenden ist.

Im obigen Beispiel preceding::foo[1] ist das Prädikat [1] Bestandteil des Lokalisierungsschrittes preceding::foo[1], während bei (preceding::foo)[1] das Prädikat [1] auf den Ausdruck (preceding::foo) angewendet wird (welcher in diesem Fall ein Lokalisierungsschritt ohne Prädikat ist).

Das folgende Beispiel stellt den Sachverhalt aus einer praxisnäheren Sicht dar. Es gibt zwar die Achse ancestor-or-self, welche neben allen Vorfahren auch den Kontextknoten auswählt, es gibt aber keine entsprechende Achse preceding-or-self, die alle Vorgänger inklusive den Kontextknoten auswählen könnte. Die gewünschte Knotenmenge muss also durch eine Vereinigung konstruiert werden: preceding::node() | self::node(). Bei der Anwendung eines oder mehrere Prädikate auf die entstehende Menge, etwa (preceding::node() | .)[@id][1], muss man beachten, dass die Knoten nun in Dokumentordnung gefiltert werden. Der Ausdruck liefert damit den ersten Knoten im Dokument, der ein Vorgänger des Knotextknotens ist und ein Attribut id besitzt, und nicht den zum Kontextknoten nächsten Knoten mit dieser Eigenschaft.

Bei Betrachtung des Beispiels (preceding-sibling::* | following-sibling::*)[1] wird klar, dass für solche Ausdrücke eine von den beteiligten Achsen abhängende Knotenordnung nicht praktikabel ist.

An dieser Stelle sei darauf hingewiesen, dass über die in [XSLT] definierte Funktion document auch Knotenmengen aus verschiedenen Dokumenten miteinander vereinigt werden können. In diesem Fall gibt es keine definierte Dokumentordnung für die Vereinigungsmenge mehr. Die Anwendung eines entsprechenden Prädikats ist damit implementationsabhängig. Entsprechendes gilt bei einer Knotenmenge, die die Attribute eines Elementes enthält.

Die Operatoren / und // verbinden einen Ausdruck und einen relativen Lokalisierungspfad. Es ist ein Fehler, wenn die Berechnung des Ausdrucks keine Knotenmenge ergibt. Der Operator / arbeitet dabei in der gleichen Weise wie in einem Lokalisierungspfad. Ebenso wie in Lokalisierungspfaden steht // abkürzend für /descendant-or-self::node()/.

Es gibt keine Objekte, die in eine Knotenmenge konvertiert werden können.

Anmerkung des Übersetzers:

Angenommen eine Variablen namens divs enthält eine Knotenmenge von diversen div-Elementen (div1, div2, etc). Dann kann mittels $divs[1] auf das erste dieser Elemente zugegriffen werden. $divs/@id liefert die Menge der id-Attributknoten der Elemente aus $divs, $divs//image liefert die Menge aller image-Elemente, die Nachkommen eines in $divs enthaltenen div-Elementes sind.

Dabei ist zu beachten, dass sich einem Ausdruck anschließende Lokalisierungsschritte immer auf die Position der Knoten im XML-Dokument beziehen und nicht auf die durch den Ausdruck berechnete Knotenmenge. Beispielsweise bestimmt $divs[1]/preceding-sibling::* den nachfolgenden Geschwisterknoten des ersten Knotens aus $divs im XML-Dokument, und nicht den "Nachfolger" in $divs, also $divs[2]. Allgemein gesprochen gibt es keinen Weg, der es erlaubt, ausgehend von einem Kontextknoten, der Element einer zuvor bestimmten Knotenmenge ist, auf die anderen Knoten dieser Menge zuzugreifen. Das betrifft insbesondere Ausdrücke, die in Prädikaten oder im Körper der XSLT-Anweisung xsl:for-each auftreten.

Ausdrücke, speziell Variablen, dürfen nur vor / und // auftreten. Es ist nicht möglich, Ausdrücke dynamisch zusammenzusetzen, wie man es etwa mit /root/$element versuchen könnte. Eine Möglichkeit, innerhalb eines Pfades dynamisch ein bestimmtes Element auszuwählen, wird im Zusammenhang mit der Funktion name vorgestellt.

Wie schon gesagt wurde, muss ein Ausdruck, dem ein Prädikat oder einer der Operatoren / und // folgt, immer eine Knotenmenge als Ergebnis liefern. Da Objekte anderer Typen nicht in eine Knotenmenge konvertiert werden können, führt die Auswertung eines Ausdrucks, der keine Knotenmenge ergibt, in diesem Fall zu einem Fehler. XPath nutzende Spezifikationen und Implementationen können jedoch explizit zusätzliche Funktionen definieren, die beliebige Objekte in Knotenmengen überführen.

[18]    UnionExpr    ::=    PathExpr
| UnionExpr '|' PathExpr
[19]    PathExpr    ::=    LocationPath
| FilterExpr
| FilterExpr '/' RelativeLocationPath
| FilterExpr '//' RelativeLocationPath
[20]    FilterExpr    ::=    PrimaryExpr
| FilterExpr Predicate

3.4 Boolesche Werte

Ein Objekt vom Typ boolean kann zwei Werte annehmen, wahr und falsch.

Die Berechnung eines or-Ausdrucks erfolgt, indem jeder der Operanden berechnet und in einen booleschen Wert wie beim Aufruf der Funktion boolean konvertiert wird. Das Ergebnis ist der Wert wahr, wenn einer der beiden Werte wahr ist und andernfalls falsch. Der rechte Operand wird nicht mehr ausgewertet, wenn der linke Operand wahr ergibt.

Die Berechnung eines and-Ausdrucks erfolgt, indem jeder der Operanden berechnet und in einen booleschen Wert wie beim Aufruf der Funktion boolean konvertiert wird. Das Ergebnis ist der Wert wahr, wenn beide Werte wahr sind und andernfalls falsch. Der rechte Operand wird nicht mehr ausgewertet, wenn der linke Operand falsch ergibt.

Anmerkung des Übersetzers:

Mit dieser Regelung lässt sich die Berechnung von Teilausdrücken und der Aufruf enthaltener Funktionen verhindern. Abgesehen von Performance-Aspekten hat sie im Zusammenhang mit XSLT allerdings nicht die gleiche Bedeutung wie in anderen Programmiersprachen.

So arbeiten alle XSLT-Funktionen ohne Seiteneffekte (sie produzieren weder Ausgaben noch ändern sie Variableninhalte), Funktionsparameter werden automatisch in den geforderten Typ konvertiert, und mathematische Operationen liefern immer einen definierten Wert. Lediglich Typfehler können auftreten, falls ein Ausdruck als Operand oder Funktionsparameter eine Knotenmenge verlangt. Allerdings gibt es in XPath keine Möglichkeit festzustellen, ob ein Teilausdruck vom Typ Knotenmenge ist.

Da sich über Erweiterungsmechanismen jedoch Funktionen definieren lassen, die die genannten Eigenschaften nicht mehr besitzen, kann über eine Verknüpfung mit or oder and der Aufruf solcher Funktionen bei Bedarf verhindert werden.

Die Berechnung eines EqualityExpr-Ausdrucks (der nicht allein ein RelationalExpr-Ausdruck ist) oder eines RelationalExpr-Ausdrucks (der nicht allein ein AdditiveExpr-Ausdruck ist) geschieht, indem die Objekte miteinander verglichen werden, die im Ergebnis der Auswertung der beiden Operanden entstehen. Die folgenden drei Absätze definieren den Vergleich zwischen den daraus resultierenden Objekten. Erst werden Vergleiche, die Knotenmengen betreffen, über Vergleiche definiert, die keine Knotenmengen betreffen; dies geschieht einheitlich für =, !=, <=, <, >= und >. Dann werden Vergleiche, die keine Knotenmengen betreffen, für = und != definiert. Schließlich werden Vergleiche, die keine Knotenmengen betreffen, für <=, <, >= und > definiert.

Wenn beide zu vergleichenden Objekte Knotenmengen sind, so liefert ein Vergleich genau dann den Wert wahr, wenn es einen Knoten aus der ersten Knotenmenge und einen Knoten aus der zweiten Knotenmenge gibt, sodass das Ergebnis des Vergleichs der Zeichenkettenwerte dieser beiden Knoten wahr ergibt. Wenn eines der zu vergleichenden Objekte eine Knotenmenge und das andere eine Zahl ist, dann liefert ein Vergleich genau dann den Wert wahr, wenn wenn es einen Knoten in der Knotenmenge gibt, sodass der Vergleich zwischen der Zahl und dem Ergebnis der Konvertierung des Zeichenkettenwerts dieses Knotens zu einer Zahl über die Funktion number wahr ergibt. Wenn eines der zu vergleichenden Objekte eine Knotenmenge und das andere eine Zeichenkette ist, dann liefert ein Vergleich genau dann den Wert wahr, wenn wenn es einen Knoten in der Knotenmenge gibt, sodass der Vergleich zwischen der Zeichenkette und dem Zeichenkettenwert dieses Knotens wahr ergibt. Wenn eines der zu vergleichenden Objekte eine Knotenmenge und das andere ein boolescher Wert ist, dann liefert ein Vergleich genau dann den Wert wahr, wenn wenn es einen Knoten in der Knotenmenge gibt, sodass der Vergleich zwischen dem booleschen Wert und dem Ergebnis der Konvertierung des Zeichenkettenwerts dieses Knotens zu einer Zahl über die Funktion boolean wahr ergibt.

Wenn keines der zu vergleichenden Objekte eine Knotenmenge ist und als Operator = oder != vorkommt, so werden die Objekte wie nachfolgend beschrieben in einen gemeinsamen Typ konvertiert und anschließend verglichen. Wenn wenigstens eines der zu vergleichenden Objekte ein boolescher Wert ist, so wird jedes Objekt in einen booleschen Wert wie bei der Anwendung der Funktion boolean konvertiert. Andernfalls, wenn wenigstens eines der zu vergleichenden Objekte eine Zahl ist, so wird jedes Objekt in eine Zahl wie bei der Anwendung der Funktion number konvertiert. Andernfalls werden beide Objekte in Zeichenketten wie bei der Anwendung der Funktion string konvertiert. Der Vergleich = liefert als Ergebnis genau dann den Wert wahr, wenn beide Objekte gleich sind; der Vergleich != liefert als Ergebnis genau dann den Wert wahr, wenn beide Objekte ungleich sind. Zahlen werden gemäß IEEE 754 [IEEE 754] verglichen. Zwei boolesche Werte sind gleich, wenn sie entweder beide wahr oder beide falsch sind. Zwei Zeichenketten sind genau dann gleich, wenn sie aus derselben Folge von UCS Zeichen bestehen.

Anmerkung: Wenn $x mit einer Knotenmenge belegt ist, dann bedeutet $x="foo" nicht dasselbe wie not($x!="foo"): der erste Vergleich ergibt genau dann wahr, wenn ein Knoten in $x den Zeichenkettenwert foo hat; der zweite ergibt genau dann wahr, wenn alle Knoten in $x den Zeichenkettenwert foo haben.

Anmerkung des Übersetzers:

Der Vergleich $x!="foo" ist genau dann wahr, wenn es wenigstens einen Knoten aus $x gibt, für den die Ungleichheit gilt, d.h. falsch wenn es keinen solchen Knoten gibt. Damit ist not($x!="foo") wahr, wenn es keinen Knoten aus $x gibt, dessen Zeichenkettenwert verschieden von foo ist, d.h. wenn alle Knoten den Zeichenkettenwert foo besitzen.

Ein häufigerer Fall dürfte der Test auf Ungleichheit sein. Man möchte z.B. feststellen, ob der Wert eines Ausdrucks verschieden von allen Kindelementen entry ist. Die Lösung lautet in diesem Fall nicht entry!="foo" (hier wird auf alle entry-Kindelemente zugegriffen und getestet, ob unter diesen eines existiert, das verschieden von der Zeichenkette "foo" ist), sondern not(entry="foo").

Bemerkenswert ist noch der Fall, dass die beteiligte Knotenmenge leer ist. Ein Vergleich @type!="warning" ist falsch, wenn kein Attribut type existiert. Dagegen liefert not(@type="warning") in diesem Fall den Wert wahr.

Es sei noch einmal darauf hingewiesen, dass für Knotenmengen mit den Operatoren = und != nicht die Identität von Knoten getestet wird, sondern die ihrer Zeichenkettenwerte. Zwei Knoten können unter Zuhilfenahme des Operators | auf Identität getestet werden, siehe Anmerkung in Kapitel [3.3 Knotenmengen].

Wenn keines der zu vergleichenden Objekte eine Knotenmenge ist und als Operator <=, <, >= oder > vorkommt, so werden beide Objekte in Zahlen konvertiert und anschließend gemäß IEEE 754 verglichen. Der Vergleich < ergibt genau dann den Wert wahr, wenn die erste Zahl kleiner als die zweite Zahl ist. Der Vergleich <= ergibt genau dann den Wert wahr, wenn die erste Zahl kleiner oder gleich der zweiten Zahl ist. Der Vergleich > ergibt genau dann den Wert wahr, wenn die erste Zahl größer als die zweite Zahl ist. Der Vergleich >= ergibt genau dann den Wert wahr, wenn die erste Zahl größer oder gleich der zweiten Zahl ist.

Anmerkung des Übersetzers:

Somit sind Vergleiche, an denen Knotenmengen beteiligt sind, dann erfüllt, wenn sich wenigstens ein Knoten aus der jeweiligen Menge finden lässt, dessen Zeichenkettenwert den Vergleich erfüllt. Insbesondere liefert der Vergleich mit wenigstens einer leeren Menge in jedem Fall den Wert falsch. Sind nur Werte verschiedener skalarer Typen beteiligt, so wird in der Rangfolge boolescher Wert — Zahl — Zeichenkette ein gemeinsamer Typ gesucht und der jeweils andere Wert konvertiert. Größenvergleiche sind nur für Zahlen definiert.

Unter Ausnutzung dieser Regeln kann z.B. die kleinste Zahl in einer Knotenmenge $set folgendermaßen bestimmt werden:

$set[not(. > $set)]

Ein Vergleich mit dem speziellen Zahlenwert NaN liefert immer den Wert falsch, selbst bei number('NaN')=number('NaN'). Bei 'NaN' handelt es sich hier nicht um eine spezielle Zeichenkette, die in den Wert NaN konvertiert wird, sondern einfach um eine, die sich nicht konvertieren lässt. Können in der Beispielmenge $set auch Knoten auftreten, deren Zeichenkettenwert sich nicht in eine Zahl konvertieren lässt, könnte man den obigen Ausdruck auf folgende, etwas unkonventionelle Weise vervollständigen:

$set[number()=number() and not(. > $set)]

Vorsicht ist geboten, wenn die Werte einer Knotenmenge vor dem Vergleich durch eine Funktion mit skalarem Argumenttyp bearbeitet werden sollen. Übergibt man die gesamte Knotenmenge der Funktion als Argument, wird nur mit dem Funktionswert des ersten Knotens verglichen. Die spezielle Semantik des Vergleichs mit Knotenmengen geht verloren. In der Anmerkung zur Funktion normalize-space wird dies an einem Beispiel ausführlicher erläutert.

XPath stellt keine Möglichkeit zur Verfügung, mit der man Zeichenketten lexikographisch der Größe nach vergleichen könnte. Abhängig vom Anwendungsfall lassen sich in XSLT solche Vergleiche durch die Programmierung rekursiver Templates oder die Benutzung des xsl:sort-Elementes realisieren.

Anmerkung: Wenn ein XPath-Ausdruck in einem XML-Dokument vorkommt, so müssen alle < und <= Operatoren gemäß den XML 1.0 Regeln geschützt werden, zum Beispiel als &lt; und &lt;=. Im folgenden Beispiel ist der Wert des Attributes test ein XPath-Ausdruck:
<xsl:if test="@value &lt; 10">...</xsl:if>
[21]    OrExpr    ::=    AndExpr
| OrExpr 'or' AndExpr
[22]    AndExpr    ::=    EqualityExpr
| AndExpr 'and' EqualityExpr
[23]    EqualityExpr    ::=    RelationalExpr
| EqualityExpr '=' RelationalExpr
| EqualityExpr '!=' RelationalExpr
[24]    RelationalExpr    ::=    AdditiveExpr
| RelationalExpr '<' AdditiveExpr
| RelationalExpr '>' AdditiveExpr
| RelationalExpr '<=' AdditiveExpr
| RelationalExpr '>=' AdditiveExpr
Anmerkung: Mit der obigen Grammatik ergibt sich folgende Vorrangfolge (kleinster Vorrang zuerst): Alle Operatoren sind links-assoziativ. Beispielsweise ist 3 > 2 > 1 äquivalent zu (3 > 2) > 1, was den Wert falsch ergibt.

Anmerkung des Übersetzers:

Der Vergleich 3 > 2 ergibt zunächst den Wert wahr. Dieses Ergebnis wird aufgrund des folgenden Vergleichsoperators > in die Zahl 1 konvertiert, sodass nun 1 > 1 berechnet wird, was den Wert falsch liefert. Auf analoge Weise kann man sich überlegen, dass der Ausdruck 2 = 1 = 0 wahr, hingegen der Ausdruck 0 = 0 = 0 falsch ergibt.

Hier ist Vorsicht geboten, da solche Ausdrücke gemäß der XPath-Grammatik erlaubt sind, aber nicht die Semantik besitzen, die man auf den ersten Blick erwarten würde. Sie verhalten sich allerdings genauso wie beispielsweise in den Programmiersprachen C und C++.

3.5 Zahlen

Ein Wert vom Typ number repräsentiert eine Gleitkommazahl. Eine Zahl kann jeden beliebigen, doppelt-genauen 64-Bit Wert des Formats IEEE 754 [IEEE 754] annehmen. Dies beinhaltet den speziellen Wert "Not-a-Number" (NaN), positiv und negativ unendlich, sowie positiv und negativ null. Für eine Zusammenfassung der wichtigsten Regeln des IEEE 754 Standards siehe Abschnitt 4.2.3 in [JLS].

Anmerkung des Übersetzers:

Die genannten speziellen Werte entstehen dann, wenn eine Rechenoperation einen Überlauf produzieren würde bzw. das Ergebnis nicht definiert ist. Es können beim Rechnen mit Zahlen in XPath keine Fehler oder Ausnahmen auftreten.

An dieser Stelle sei bereits kurz auf die Produktion für Number in [3.7 Lexikalische Struktur] hingewiesen. Zahlen in XPath sind Gleitkommazahlen ohne Exponentendarstellung. Eine Schreibweise 2.99792E+08 ist nicht zulässig. Sie können ein negatives, aber kein explizites positives Vorzeichen besitzen. Soll einer der speziellen Werte wie z.B. positiv unendlich verwendet werden, muss dieser ermittelt werden, etwa durch 1 div 0.

Es gibt in XPath weder einen speziellen Typ für ganzzahlige Werte noch gesonderte Zahlendarstellungen, die eine Zahl als Oktal- oder Hexadezimalzahl interpretieren, wie dies in vielen Programmiersprachen möglich ist.

Die numerischen Operatoren konvertieren ihre Operanden in Zahlen so wie bei einem Aufruf der Funktion number.

Der Operator + addiert.

Der Operator - subtrahiert.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] ist die Semantik des einstelligen Operators - nicht spezifiziert. Stattdessen muss dieser letzte Absatz lauten:

Der zweistellige Operator - subtrahiert. Der einstellige Operator - berechnet die Negation. Beachten Sie, dass -0 negativ null ergibt.
Anmerkung: Da XML innerhalb von Namen das Zeichen - erlaubt, muss der Operator - typischerweise von einem Leerraumzeichen angeführt werden. Zum Beispiel ergibt foo-bar eine Knotenmenge, die die Kindelemente namens foo-bar enthält; foo - bar ergibt die Differenz aus den Werten, die durch Konvertierung des Zeichenkettenwertes des ersten foo-Kindelements in eine Zahl und durch Konvertierung des Zeichenkettenwertes des ersten bar-Kindelements in eine Zahl entstehen.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] ist die Semantik des Operators * nicht spezifiziert. An dieser Stelle muss folgender Absatz eingefügt werden:

Der Operator * berechnet eine Gleitkomma-Multiplikation gemäß IEEE 754. Beachten Sie: falls das Ergebnis nicht NaN ist, ist das Ergebnis genau dann positiv, wenn beide Operanden das gleiche Vorzeichen besitzen.

Das Zeichen * dient zugleich als Knotentest zur Auswahl beliebiger Elemente. Welche Semantik ein * innerhalb eines XPath-Ausdrucks hat, hängt damit von den umgebenden Token in diesem Ausdruck ab (siehe [3.7 Lexikalische Struktur]).

Der Operator div berechnet eine Gleitkomma-Division gemäß IEEE 754.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Satz eingefügt werden:

Beachten Sie: falls das Ergebnis nicht NaN ist, ist das Ergebnis genau dann positiv, wenn beide Operanden das gleiche Vorzeichen besitzen.

Der Schrägstrich / ist nicht der Divisionsoperator, da dieser bereits als Pfadoperator zum Verbinden von Lokalisierungsschritten sowie als Symbol für den Wurzelknoten benutzt wird. Im Gegensatz zum Zeichen * gibt es hier nicht mehrere Interpretationsmöglichkeiten.

Der Operator mod liefert den Rest einer ganzzahligen Division. Beispiele:

Anmerkung: mod berechnet dasselbe wie der Operator % in Java und ECMAScript.
Anmerkung: Er berechnet nicht dasselbe wie die IEEE 754 Rest-Operation, welche den Rest einer gerundeten Division liefert.

Anmerkung des Übersetzers:

Der mod-Operator berechnet den genauen Rest, der sich bei der ganzzahligen Division zweier Gleitkommazahlen ergibt, ohne die Operanden zuvor auf ganze Zahlen zu runden.

Numerische Ausdrücke
[25]    AdditiveExpr    ::=    MultiplicativeExpr
| AdditiveExpr '+' MultiplicativeExpr
| AdditiveExpr '-' MultiplicativeExpr
[26]    MultiplicativeExpr    ::=    UnaryExpr
| MultiplicativeExpr MultiplyOperator UnaryExpr
| MultiplicativeExpr 'div' UnaryExpr
| MultiplicativeExpr 'mod' UnaryExpr
[27]    UnaryExpr    ::=    UnionExpr
| '-' UnaryExpr

3.6 Zeichenketten

Zeichenketten bestehen aus einer Folge von null oder mehr Zeichen, wobei Zeichen so wie in der XML-Empfehlung [XML] definiert sind. Ein einzelnes XPath-Zeichen entspricht damit einem einzelnen abstrakten Unicode-Zeichen mit einem einzelnen korrespondierenden skalaren Wert (siehe [Unicode]); dies unterscheidet sich allerdings von einem 16-Bit-kodierten Unicode-Zeichen: die durch Unicode definierte kodierte Zeichenrepräsentation eines abstrakten Zeichens mit einem skalaren Wert größer als U+FFFF ist ein Paar von 16-Bit Unicode-Codes (ein Surrogat-Paar). In vielen Programmiersprachen wird eine Zeichenkette als Folge von 16-Bit-kodierten Unicode-Zeichen repräsentiert; XPath-Implementationen in solchen Sprachen müssen sicherstellen, dass ein Surrogat-Paar korrekt als einzelnes XPath-Zeichen behandelt wird.

Anmerkung: In Unicode ist es möglich, dass zwei Zeichenketten als identisch anzusehen sind, obwohl sie aus unterschiedlichen Folgen abstrakter Unicode-Zeichen bestehen. Zum Beispiel können einige Akzentzeichen entweder in einer vordefinierten (precomposed) oder einer zerlegten (decomposed) Form repräsentiert werden. Damit können XPath-Ausdrücke unerwartete Resultate liefern, es sei denn, sowohl die Zeichen im XPath-Ausdruck als auch die im XML-Dokument wurden zu einer kanonischen Form normalisiert. Siehe [Character Model].

Anmerkung des Übersetzers:

Ein zusammengesetztes Zeichen, das sich auch als vordefiniertes Zeichen kodieren lässt, wird durch einen einzigen Unicode-Code repräsentiert. Beispielsweise lässt sich der Umlaut »ü« als U+00FC darstellen. Zugleich kann dieser Buchstabe auch wie jedes zusammengesetzte Zeichen in der zerlegten Form durch die Folge der beiden Codes U+0075 (»u«) und U+0308 (combining diaeresis) kodiert werden.

3.7 Lexikalische Struktur

Beim Zerlegen in einzelne Token wird immer das längstmögliche Token zurückgeliefert.

Zur besseren Lesbarkeit können Leerraumzeichen innerhalb von Ausdrücken verwendet werden, auch wenn es nicht explizit durch die Grammatik erlaubt wurde: ExprWhitespace kann frei innerhalb von Ausdrücken vor oder nach beliebigen ExprToken eingefügt werden.

Anmerkung des Übersetzers:

An dieser Stelle sei auf die Anmerkung zum Operator für die Subtraktion, das zweistellige Minus, in [3.5 Zahlen] hingewiesen. Der erste Absatz legt fest, dass »foo-bar« nur als einzelnes Token interpretiert werden darf und nicht als Folge der Token »foo«, »-« und »bar«. Der zweite Absatz erlaubt nun explizit, beispielsweise den Minus-Operator mittels Leerraumzeichen als einzeln zu interpretierendes Token zu kennzeichnen.

Üblicherweise unterscheidet man bei der Definition einer Sprache zwischen lexikalischen Produktionen, die den Aufbau der lexikalischen Einheiten, sogenannter Token festlegen, und syntaktischen Produktionen, die die mögliche Kombination dieser Token zu komplexeren Konstrukten beschreiben. In der XPath-Spezifikation sind diese beiden Arten von Produktionen allerdings nicht streng voneinander abgegrenzt. Der Hauptunterschied zwischen lexikalischen und syntaktischen Produktionen besteht darin, dass zwischen einzelnen Token Leerraumzeichen auftreten dürfen, nicht jedoch innerhalb eines Tokens. Die Produktion für das Nichtterminal ExprToken stellt damit die oberste lexikalische Produktion dar. Daraus ergibt sich, dass ein Leerzeichen zwischen @ und einem QName zur Abkürzung der attribute-Achse erlaubt ist, nicht aber zwischen $ und einem QName bei Variablenreferenzen.

Die folgenden speziellen Regeln für die Zerlegung in Token müssen in der angegebenen Reihenfolge angewendet werden, um die Grammatik ExprToken eindeutig zu machen:

Anmerkung des Übersetzers:

Im zweiten Aufzählungspunkt des Originaldokuments hat sich ein Fehler eingeschlichen. Da Funktionsnamen mit einem Präfix ausgestattet sein können, muss laut Errata-Dokument [XPath Errata] auf QName statt auf NCName verwiesen werden. Alle Standardfunktionen aus XPath, XSLT und XPointer besitzen zwar nur Namen ohne Präfix, der Erweiterungsmechanismus in XSLT erlaubt jedoch XSLT-Implementationen, zusätzliche Funktionen aus einem proprietären Namensraum zur Verfügung zu stellen.

Das hier diskutierte Problem der Mehrdeutigkeit umgeht man in vielen anderen Programmiersprachen durch die Definition von Schlüsselwörtern, die dann für frei wählbare Bezeichner nicht mehr zur Verfügung stehen. Ein XML-Autor ist jedoch frei in seiner Wahl für Element- und Attributnamen, also muss auch die Sprache XPath damit umgehen zu können. Die gefundene Regelung ermöglicht eine kompakte Schreibweise für XPath-Ausdrücke und bürdet die Last der eindeutigen Interpretation der jeweiligen XPath-Implementation auf.

Die folgenden Beispiele zeigen, wie Bezeichner (und der *-Operator) abhängig vom Kontext unterschiedlich interpretiert werden müssen:

  • ***

    bestimmt jeweils den in eine Zahl konvertieren Zeichenkettenwert der ersten Knoten in den durch * repräsentierten Knotenmengen aller Kindelemente und multipliziert diese miteinander, d.h. das erste und dritte * werden als Lokalisierungspfad, das mittlere * als Multiplikationsoperator interpretiert.

  • and or mod

    ergibt den Wert wahr, wenn der Kontextknoten wenigstens ein Kindelement namens and oder ein Kindelement namens mod besitzt (Operatorname versus Elementname).

  • text and text()

    ergibt den Wert wahr, wenn der Kontextknoten sowohl wenigstens ein Element namens text als auch wenigstens einen Textknoten als Kinder besitzt (Knotentyp versus Elementname).

  • position() = position

    ergibt den Wert wahr, wenn die aktuelle Kontextposition mit dem in eine Zahl konvertierten Zeichenkettenwert eines Kindelements namens position übereinstimmt (Funktionsname versus Elementname).

  • parent or parent::child

    ergibt den Wert wahr, wenn der Kontextknoten ein Kindelement namens parent oder ein Elternelement namens child besitzt (Achsenname versus Elementname).

Lexikalische Struktur von Ausdrücken
[28]    ExprToken    ::=    '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
| NameTest
| NodeType
| Operator
| FunctionName
| AxisName
| Literal
| Number
| VariableReference
[29]    Literal    ::=    '"' [^"]* '"'
| "'" [^']* "'"
[30]    Number    ::=    Digits ('.' Digits?)?
| '.' Digits
[31]    Digits    ::=    [0-9]+
[32]    Operator    ::=    OperatorName
| MultiplyOperator
| '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>='
[33]    OperatorName    ::=    'and' | 'or' | 'mod' | 'div'
[34]    MultiplyOperator    ::=    '*'
[35]    FunctionName    ::=    QName - NodeType
[36]    VariableReference    ::=    '$' QName
[37]    NameTest    ::=    '*'
| NCName ':' '*'
| QName
[38]    NodeType    ::=    'comment'
| 'text'
| 'processing-instruction'
| 'node'
[39]    ExprWhitespace    ::=    S

4 Bibliothek der Grundfunktionen

Dieser Abschnitt beschreibt die Funktionen, die bei einer XPath-Implementation immer in der bei der Auswertung von Ausdrücken benutzten Funktionsbibliothek enthalten sein müssen.

Jede Funktion in der Funktionsbibliothek wird über einen Funktionsprototypen spezifiziert, der den Rückgabetyp, den Namen der Funktion und die Typen der Argumente angibt. Falls ein Argument von einem Fragezeichen gefolgt wird, so ist es optional; andernfalls ist es obligatorisch.

Anmerkung des Übersetzers:

Ein Funktionsargument, das von einem Stern * gefolgt wird, darf kein-, ein- oder mehrmals auftreten. Der Argumenttyp object steht für einen beliebigen Typ.

4.1 Funktionen auf Knotenmengen

Funktion: number last()

Die Funktion last liefert eine Zahl, die gleich der Kontextgröße des Kontexts des ausgewerteten Ausdrucks ist.

Funktion: number position()

Die Funktion position liefert eine Zahl, die gleich der Kontextposition im Kontext des ausgewerteten Ausdrucks ist.

Funktion: number count(node-set)

Die Funktion count liefert die Anzahl der Knoten der übergebenen Knotenmenge.

Anmerkung des Übersetzers:

Für den letzten Knoten einer Knotenmenge gilt damit die Gleichheit position()=last(). Beachten Sie, dass die Nummerierung der Knoten bei 1 beginnt.

Während last also die Kontextgröße zurückgibt, d.h. die Anzahl der Knoten der Knotenmenge, in der sich der Kontextknoten befindet, berechnet count die Anzahl der Knoten einer beliebigen als Argument zu übergebenden Knotenmenge. Es gibt keinen XPath-Ausdruck, der für einen beliebigen Knoten dessen Position in einer vorgegebenen Knotenmenge berechnet.

In bestimmten Situationen lässt sich jedoch das Wissen über die Art der Beziehungen der Knoten in der Knotenmenge ausnutzen. Möchte man beispielsweise herausfinden, welche Position das erste para-Kind mit dem Attribut type="warning" unter allen para-Kindern besitzt, kann man einfach die diesem Element vorhergehenden para-Geschwister zählen und 1 addieren:

count(para[@type="warning"]/preceding-sibling::para)+1

Diese Methode funktioniert hier deshalb, weil klar ist, dass alle para-Elemente Geschwister sind und auf die vorherigen Knoten der Menge daher über die Achse preceding-sibling zugegriffen werden kann. Wenn nicht bekannt ist, wie die Knotenmenge gebildet wurde, können auch nicht die anderen Knoten bestimmt und gezählt werden.

In Kapitel [3.3 Knotenmengen] wird im Zusammenhang mit dem Mengenvereinigungsoperator | gezeigt, wie die Funktion count zur Bestimmung von Durchschnitt und Differenz zweier Mengen genutzt werden kann.

Funktion: node-set id(object)

Die Funktion id wählt Elemente anhand ihrer eindeutigen ID aus (siehe [5.2.1 Eindeutige IDs]). Wenn als Argument eine Knotenmenge übergeben wird, so ergibt sich das Ergebnis aus der Vereinigung der Knotenmengen, die durch den Aufruf von id mit dem Zeichenkettenwert jedes Knotens aus der übergebenen Knotenmenge berechnet werden. Ist das Argument der Funktion id von einem beliebigen anderen Typ, so wird es in eine Zeichenkette wie bei einem Aufruf der Funktion string konvertiert; die Zeichenkette wird in eine durch Leerraumzeichen getrennte Liste von Token aufgeteilt (Leerraumzeichen sind beliebige Folgen von Zeichen, die auf die Produktion S passen); das Ergebnis ist eine Knotenmenge, die die Elemente aus dem Dokument des Kontextknotens enthält, die eine eindeutige ID mit dem gleichen Wert wie eines der Token der Liste besitzen.

Anmerkung des Übersetzers:

Diese Funktion ermöglicht die Auswertung von Attributen des Typs IDREF bzw. IDREFS. Da ein IDREF-Wert an ein Element im gleichen XML-Dokument als ID vergeben worden sein muss, lässt sich dieses Element mit Hilfe der Funktion id bestimmen. Handelt es sich um mehrere IDs als Wert eines IDREFS-Attribut, liefert id alle zugehörigen Elemente als Knotenmenge.

Entsprechend der obigen Definition gilt also:

id("foo bar baz") = id("foo") | id("bar") | id("baz")

Die Knoten in der Ergebnisknotenmenge werden durch ein folgendes Prädikat in Dokumentordnung gefiltert und nicht in der Reihenfolge der angegebenen IDs.

Dagegen wird bei der Übergabe einer Knotenmenge, wie im Beispiel id(foo), von allen Knoten der Menge deren Zeichenkettenwert als Parameter verarbeitet und dieser wie ein IDREFS-Attribut interpretiert. Das Ergebnis ist die Vereinigung aller auf diese Weise bestimmten Knoten.

Die Funktion id kann aber nur korrekt arbeiten, wenn ID-wertige Attribute als solche erkannt werden. Dazu muss die DTD bekannt und vom Parser ausgewertet worden sein. Dies ist einer der wenigen Fälle, in denen das Ergebnis eines XPath-Ausdrucks von der Kenntnis der DTD des Dokuments abhängt. Fehlt diese Information, liefert id immer eine leere Knotenmenge.

Es gibt keine komplementäre Funktion, die für ein Element dessen ID zurückliefert. Unter Zuhilfennahme von id lässt sich diese Information allerdings herausfinden. Gesucht ist nämlich genau das Attribut, für das die Funktion id den Elternknoten dieses Attributs liefert:

@*[id(.) and count(id(.)|..)=1]

Funktion: string local-name(node-set?)

Die Funktion local-name liefert den lokalen Teil des erweiterten Namens des ersten Knotens in der Argumentknotenmenge bezüglich der Dokumentordnung. Falls die übergebene Knotenmenge leer ist oder der erste Knoten keinen erweiterten Namen besitzt, wird eine leere Zeichenkette zurückgegeben. Wird kein Argument übergeben, wird stattdessen eine Knotenmenge mit dem Kontextknoten als einzigem Element benutzt.

Anmerkung des Übersetzers:

Für Element- und Attributknoten gilt damit, dass die Funktion local-name den dem Doppelpunkt folgenden Teil des QName zurückgibt bzw. den vollständigen Namen, wenn dieser kein Präfix enthält. Die folgenden Beispiele demonstrieren dies unter der Voraussetzung, dass der als jeweiliges Argument übergebene Lokalisierungspfad nicht die leere Knotenmenge ergibt:

local-name(xhtml:body) = "body"
local-name(@xlink:href) = "href"
local-name(para) = "para"

Für Namensraum-Knoten liefert local-name das zugewiesene Präfix, also beispielsweise für die Deklaration xmlns:xlink="http://www.w3.org/1999/xlink" die Zeichenkette »xlink«. Für Namensraum-Knoten, die den voreingestellten Namensraum repräsentieren, wird die leere Zeichenkette zurückgegeben.

Für Processing Instructions liefert local-name das jeweilige Ziel, also beispielsweise für <?xml-stylesheet href='style.xsl'?> die Zeichenkette »xml-stylesheet«.

Für Textknoten, Kommentare und den Wurzelknoten liefert local-name die leere Zeichenkette.

Funktion: string namespace-uri(node-set?)

Die Funktion namespace-uri liefert den Namensraum-URI des erweiterten Namens des ersten Knotens in der Argumentknotenmenge bezüglich der Dokumentordnung. Falls die übergebene Knotenmenge leer ist, der erste Knoten keinen erweiterten Namen besitzt oder der Namensraum-URI des erweiterten Namens leer ist, wird eine leere Zeichenkette zurückgegeben. Wird kein Argument übergeben, wird stattdessen eine Knotenmenge mit dem Kontextknoten als einzigem Element benutzt.

Anmerkung: Die von der Funktion namespace-uri zurückgegebene Zeichenkette ist außer für Element- oder Attributknoten immer leer.

Anmerkung des Übersetzers:

Beispiele: namespace-uri(xhtml:body) liefert den zum Präfix xhtml gehörenden Namensraum-URI (z.B. »http://www.w3.org/1999/xhtml«), entsprechend ergibt namespace-uri(@xlink:href) die Zeichenkette »http://www.w3.org/1999/xlink«, falls das Präfix xlink an diesen URI gebunden wurde. Für Elementknoten aus dem voreingestellten Namensraum liefert namespace-uri den dazugehörigen URI. Für Element- und Attributknoten, die keinem Namensraum angehören, wird die leere Zeichenkette zurückgegeben.

Funktion: string name(node-set?)

Die Funktion name liefert eine Zeichenkette mit einem QName, die den erweiterten Namen des ersten Knotens in der Argumentknotenmenge bezüglich der Dokumentordnung repräsentiert. Der QName muss den erweiterten Namen unter Berücksichtigung der Namensraum-Deklarationen repräsentieren, die für den Knoten gültig sind, dessen erweiterter Name repräsentiert wird. Typischerweise ist das der QName, der in der XML-Quelle vorkommt. Das muss nicht der Fall sein, wenn es für den Knoten Namensraum-Deklarationen gibt, die dem gleichen Namensraum mehrere Präfixe zuordnen. Allerdings kann eine Implementation Informationen über das Originalpräfix speichern; in diesem Fall kann die Implementation sicherstellen, dass der zurückgegebene String immer der in der XML-Quelle benutzte QName ist. Falls die übergebene Knotenmenge leer ist oder der erste Knoten keinen erweiterten Namen besitzt, wird eine leere Zeichenkette zurückgegeben. Wird kein Argument übergeben, wird stattdessen eine Knotenmenge mit dem Kontextknoten als einzigem Element benutzt.

Anmerkung: Die von der Funktion name gelieferte Zeichenkette ist die gleiche wie die von der Funktion local-name gelieferte, außer für Element- und Attributknoten.

Anmerkung des Übersetzers:

Für einen folgendermaßen definierten Elementknoten

<x:foo xmlns:x="urn:bar" xmlns:y="urn:bar" />

darf die Funktion name damit die Zeichenkette »y:foo« liefern, da durch das Präfix y der gleichen Namensraum repräsentiert wird wie durch x.

Die drei Funktionen local-name, namespace-uri und name werden in der folgenden Tabelle kurz zusammengefasst. Das Zeichen »-« steht dabei für die leere Zeichenkette:

local-name namespace-uri name
[5.1 Wurzelknoten] - - -
[5.2 Elementknoten] Name ohne Präfix URI des Namensraums, in dem sich das Element befindet voller Name
[5.3 Attributknoten] Name ohne Präfix URI des Namensraums, in dem sich das Attribut befindet voller Name
[5.4 Namensraum-Knoten] Namensraum-Präfix - Namensraum-Präfix
[5.5 Processing-Instruction-Knoten] Ziel - Ziel
[5.6 Kommentarknoten] - - -
[5.7 Textknoten] - - -

Diese Funktionen erwarten als Argument zwar eine Knotenmenge, werten jedoch immer nur den ersten Knoten bezüglich der Dokumentordnung aus. Der zugrundeliegende Begriff erweiterter Name wird in Kapitel [5 Datenmodell] erläutert.

Über den Umweg, den Namen eines Knotens auszuwerten, lassen sich Knotentests variabel beschreiben. Möchte man beispielsweise den Typ eines Nachkommen-Elementes parametrisieren, kann man nicht descendant::$name verwenden. Mittels der Funktionen local-name und namespace-uri lässt sich das Problem lösen, indem zunächst alle Nachkommen-Elemente in die Ausgangsknotenmenge aufgenommen und anschließend innerhalb eines Prädikats diejenigen mit dem richtigen Namen und dem richtigen Namensraum herausgefiltert werden:

descendant::*[local-name()=$lname and namespace-uri()=$uri]

Für XML-Dokumente, die keinen Gebrauch von Namensräumen machen, reicht bereits ein Vergleich mit der von der Funktion name gelieferten Zeichenkette.

4.2 Zeichenkettenfunktionen

Funktion: string string(object?)

Die Funktion string konvertiert ein Objekt in eine Zeichenkette wie folgt:

Wird kein Argument übergeben, wird stattdessen eine Knotenmenge mit dem Kontextknoten als einzigem Element benutzt.

Anmerkung: Die Funktion string ist nicht dafür gedacht, Zahlen in Zeichenketten zu konvertieren, die an Nutzer ausgegeben werden. Die in [XSLT] definierte Funktion format-number und das ebenso dort definierte Element xsl:number stellen diese Funktionalität bereit.

Funktion: string concat(string, string, string*)

Die Funktion concat liefert die Verkettung ihrer Argumente.

Funktion: boolean starts-with(string, string)

Die Funktion starts-with liefert den logischen Wert wahr, falls die im ersten Argument übergebene Zeichenkette mit der im zweiten Argument übergebenen Zeichenkette beginnt, und andernfalls falsch.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Satz ergänzt werden:

Wenn das zweite Argument die leere Zeichenkette ist, wird der Wert wahr zurückgegeben.

Funktion: boolean contains(string, string)

Die Funktion contains liefert den logischen Wert wahr, falls die im ersten Argument übergebene Zeichenkette die im zweiten Argument übergebene Zeichenkette enthält, und andernfalls falsch.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Satz ergänzt werden:

Wenn das zweite Argument die leere Zeichenkette ist, wird der Wert wahr zurückgegeben.

Funktion: string substring-before(string, string)

Die Funktion substring-before liefert aus der im ersten Argument übergebenen Zeichenkette die Teilzeichenkette, die vor dem ersten Auftreten der im zweiten Argument übergebenen Zeichenkette steht, bzw. die leere Zeichenkette, falls die erste Zeichenkette nicht die zweite enthält. Zum Beispiel liefert substring-before("1999/04/01","/") das Ergebnis 1999.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Satz ergänzt werden:

Wenn das zweite Argument die leere Zeichenkette ist, wird die leere Zeichenkette zurückgegeben.

Funktion: string substring-after(string, string)

Die Funktion substring-after liefert aus der im ersten Argument übergebenen Zeichenkette die Teilzeichenkette, die nach dem ersten Auftreten der im zweiten Argument übergebenen Zeichenkette steht, bzw. die leere Zeichenkette, falls die erste Zeichenkette nicht die zweite enthält. Zum Beispiel liefert substring-after("1999/04/01","/") das Ergebnis 04/01 und substring-after("1999/04/01","19") liefert 99/04/01.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Satz ergänzt werden:

Wenn das zweite Argument die leere Zeichenkette ist, wird die im ersten Argument übergebene Zeichenkette zurückgegeben.

Funktion: string substring(string, number, number?)

Die Funktion substring liefert aus der im ersten Argument übergebenen Zeichenkette die Teilzeichenkette, die an der im zweiten Argument angebenen Position beginnt und die im dritten Argument angebenene Länge besitzt. Zum Beispiel liefert substring("12345",2,3) das Ergebnis "234". Falls kein drittes Argument angegeben wird, liefert die Funktion die Teilzeichenkette, die an der im zweiten Argument angegebenen Position beginnt und bis zum Ende der Zeichenkette reicht. Zum Beispiel liefert substring("12345",2) das Ergebnis "2345".

Genauer gesagt wird für jedes Zeichen der Zeichenkette (siehe [3.6 Zeichenketten]) eine numerische Position angenommen: die Position des ersten Zeichens ist 1, die Position des zweiten Zeichens ist 2 und so weiter.

Anmerkung: Dies unterscheidet sich von Java und ECMAScript, in denen die Methode String.substring die Position des ersten Zeichens mit 0 definiert.

Die zurückgegebene Teilzeichenkette enthält die Zeichen, deren Position größer oder gleich dem gerundeten Wert des zweiten Arguments ist und, falls ein drittes Argument übergeben wurde, kleiner als die Summe des gerundeten Wertes des zweiten und des gerundeten Wertes des dritten Arguments; Vergleich und Addition folgen den Standardregeln von IEEE 754; die Rundung erfolgt so, wie durch die Funktion round. Die folgenden Beispiele illustrieren einige unübliche Fälle:

Anmerkung des Übersetzers:

Die letzten vier Beispiele werden plausibel, wenn man die Definition für substring wortgetreu anwendet und beachtet, dass ein Vergleich mit dem Wert NaN immer falsch sowie jede Gleitkommazahl kleiner als positiv unendlich ist.

Mit Hilfe eines ähnlich gearteten Aufrufs dieser Funktion können bedingte Ausdrücke für Zeichenketten und damit auch Zahlen simuliert werden. Ein bedingter Ausdruck liefert abhängig von der Auswertung eines logischen Ausdrucks einen von zwei möglichen vorgegebenen Werten. Für Knotenmengen wurde die analoge Funktionalität im Zusammenhang mit dem Vereinigungsoperator | bereits in Kapitel [3.3 Knotenmengen] vorgestellt.

Unter Ausnutzung der Tatsache, dass ein logischer Wert wahr nach 1 und ein logischer Wert falsch nach 0 konvertiert wird (siehe Regeln bei der Funktion number), ergibt der Ausdruck

substring(string, 1 div boolean-test)

den Wert string, falls boolean-test wahr ist und ansonsten die leere Zeichenkette. Die vollständige Formulierung eines bedingten Ausdrucks sieht damit folgendermaßen aus:

concat(substring(true-string, 1 div boolean-test),
       substring(false-string, 1 div not(boolean-test)))

Solche Ausdrücke können beim Sortieren in XSLT eingesetzt werden, wenn der zu benutzende Sortierschlüssel von einer aktuell auszuwertenden Bedingung abhängt. Allerdings werden sie bei komplexeren Bedingungen schnell unübersichtlich.

Funktion: number string-length(string?)

Die Funktion string-length liefert die Anzahl der Zeichen der Zeichenkette (siehe [3.6 Zeichenketten]). Falls kein Argument übergeben wurde, wird der in eine Zeichenkette konvertierte Kontextknoten angenommen, mit anderen Worten der Zeichenkettenwert des Kontextknotens.

Anmerkung des Übersetzers:

Es gibt in XPath keine Funktion ends-with, die analog zu starts-with bestimmt, ob eine Zeichenkette mit einer anderen endet. Mit Hilfe der Funktionen substring und string-length kann diese Funktionalität jedoch nachgebildet werden. ends-with($str1, $str2) würde den Wert wahr liefern, falls gilt:

$str2 = substring($str1, string-length($str1) - string-length($str2) + 1)

Für das Auffüllen einer Zeichenkette von links mit Leerzeichen (z.B. für eine rechtsbündige Textausgabe) erweisen sich die Funktionen concat, substring und string-length sowie eine ausreichend lange, ausschließlich aus Leerzeichen bestehende Zeichenkette als gute Helfer:

concat(substring("                                             ",
                 1, $width - string-length($eingabe)), $eingabe)

Funktion: string normalize-space(string?)

Die Funktion normalize-space liefert als Ergebnis die übergebene Zeichenkette mit normalisiertem Leerraum zurück, d.h. führender und abschließender Leerraum wird entfernt, Folgen von mehreren Leerraumzeichen werden durch ein einzelnes Leerzeichen ersetzt. Leerraumzeichen sind jene, die durch die Produktion S in XML definiert sind. Falls kein Argument übergeben wurde, wird der in eine Zeichenkette konvertierte Kontextknoten angenommen, mit anderen Worten der Zeichenkettenwert des Kontextknotens.

Anmerkung des Übersetzers:

Diese Funktion verarbeitet eine übergebene Zeichenkette in der gleichen Weise, wie ein XML-Prozessor nach Ersetzung aller Referenzen nicht-CDATA-Attribute behandelt, siehe Kapitel 3.3.3 in [XML, 2nd Edition].

Zur Erläuterung sei das folgende Beispiel angegeben. Häufig finden sich in XML-Dokumenten Textdaten, die folgendermaßen ausgezeichnet sind:

<name>
   Otto Normal
</name>

Der Zeichenkettenwert des Elementes name enthält neben der wichtigen Information über Otto Normal auch alle Leerraumzeichen, also den Zeilenumbruch nach dem Start-Tag <name>, die Leerzeichen vor Otto und den Zeilenumbruch inklusive eventueller Leerzeichen vor dem schließenden End-Tag. Ein Vergleich für den Kontextknoten name

.="Otto Normal"

liefert also nicht das erhoffte Ergebnis, sondern schlägt fehl. Korrekt ist in diesem Fall stattdessen ein Vergleich mit dem normalisierten Wert des Knotens:

normalize-space()="Otto Normal"

Am Beispiel normalize-space soll an dieser Stelle vor einer Falle gewarnt werden, in die man bei der Übergabe von Knotenmengen an Funktionen mit skalaren Parametertypen leicht geraten kann. Angenommen, der Name Otto Normal kommt mehrfach vor, und man möchte nur den ersten dieser name-Knoten bearbeiten. In diesem Fall kann man z.B. verlangen, dass keiner der Vorgänger den gleichen Namen hat. Ist eine Normalisierung nicht erforderlich, lautet der Test einfach:

.="Otto Normal" and not(preceding-sibling::name="Otto Normal")

Muss man aber normalisieren, erweist sich der folgende Test als ungeeignet:

normalize-space()="Otto Normal" and
not(normalize-space(preceding-sibling::name)="Otto Normal")

Da die Funktion normalize-space als Argument eine Zeichenkette erwartet, wird die übergebene Knotenmenge mit der Funktion string konvertiert. Es wird also letztlich nur der erste Knoten (bezüglich der Dokumentordnung) der übergebenen Knotenmenge durch normalize-space ausgewertet und damit nur getestet, ob der erste name-Knoten einen von »Otto Normal« verschiedenen normalisierten Zeichenkettenwert besitzt. Die Lösung besteht in solchen Fällen darin, den Test in ein Prädikat zu verschieben:

normalize-space()="Otto Normal" and
not(preceding-sibling::name[normalize-space()="Otto Normal"])

Funktion: string translate(string, string, string)

Die Funktion translate liefert als Ergebnis die im ersten Argument übergebene Zeichenkette, wobei jedes Vorkommen eines Zeichens aus der im zweiten Argument übergebenen Zeichenkette ersetzt wird durch das Zeichen an der korrespondierenden Position aus der im dritten Argument übergebenen Zeichenkette. Zum Beispiel liefert translate("bar","abc","ABC") die Zeichenkette BAr. Wenn es im zweiten Argument ein Zeichen gibt, für das kein korrespondierendes Zeichen im dritten Argument existiert (weil das zweite Argument länger ist als das dritte), so werden alle Vorkommen dieses Zeichens im ersten Argument entfernt. Zum Beispiel liefert translate("--aaa--","abc-","ABC") das Ergebnis "AAA". Falls ein Zeichen mehrmals im zweiten Argument vorkommt, bestimmt das erste Auftreten das Ersetzungszeichen. Falls die im dritten Argument übergebene Zeichenkette länger ist als die zweite, so werden überzählige Zeichen ignoriert.

Anmerkung: Die Funktion translate ist keine ausreichende Lösung für die Umwandlung zwischen Groß- und Kleinschreibung in allen Sprachen. Eine zukünftige Version von XPath kann zusätzliche Funktionen für diese Umwandlung zur Verfügung stellen.

Anmerkung des Übersetzers:

Für deutsche Umlaute reicht sie im allgemeinen aus. Möchte man in einem Stylesheet an mehreren Stellen Klein- in Großschreibung umwandeln, bietet es sich an, geeignete Variablen zu definieren und fortan diese zu benutzen.

In XSLT sähe das folgermaßen aus:

<xsl:variable name="upper-case" 
              select="'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ'" />
<xsl:variable name="lower-case"
              select="'abcdefghijklmnopqrstuvwxyzäöü'" />

...
<xsl:if test="translate(firma, $lower-case, $upper-case) = 'XYZ GMBH'">
   ...
</xsl:if>

Allerdings stößt man schon beim Buchstaben »ß« an die Grenzen der Funktion translate. Die Ersetzung von »ß« durch die beiden Buchstaben »SS« ist auf diese Weise nicht möglich, weil der Ersetzungstext länger als ein Zeichen ist.

Allgemein gilt, dass die Funktion translate kein Mittel zum Ersetzen von beliebigen Teilzeichenketten ist. Ein einmaliges Ersetzen im Sinne von replace($string, $from, $to) kann durch

concat(substring-before($string, $from), $to,
       substring-after($string, $from))

ausgedrückt werden. XPath 1.0 stellt keine Mittel bereit, alle Vorkommen von $from in $string durch $to zu ersetzen. Dies wird sich in einer zukünftigen XPath-Version ändern [XPath Requirements 2.0].

Mit der Funktion translate lassen sich darüberhinaus sehr einfach ausgewählte Zeichen aus einer Zeichenkette entfernen, indem als drittes Argument eine leere Zeichenkette übergeben wird. Dies kann beispielsweise für den Test genutzt werden, ob eine Zeichenkette $string nur die in $allowed-char aufgezählten Zeichen enthält:

translate($string, $allowed-char, "") = ""

4.3 Boolesche Funktionen

Funktion: boolean boolean(object)

Die Funktion boolean konvertiert ihr Argument in einen Boolean-Wert wie folgt:

Anmerkung des Übersetzers:

Während das Argument der Funktionen string und number optional ist, beim Fehlen damit der Kontextknoten angenommen wird, ist das Argument für die Funktion boolean obligatorisch. Eine analoge Definition, die gegebenenfalls auf den Kontextknoten zurückgreift, würde auch nicht viel Sinn haben, da in diesem Fall die Funktion boolean den Wert wahr liefern müsste - der Kontextknoten ist schließlich immer vorhanden.

Funktion: boolean not(boolean)

Die Funktion not liefert den Wert wahr wenn ihr Argument falsch ist und ansonsten falsch.

Anmerkung des Übersetzers:

Im Unterschied zu den Operatoren and und or, die in den Produktionen OrExpr bzw. AndExpr definiert werden, handelt es sich bei not um eine Funktion.

Funktion: boolean true()

Die Funktion true liefert den Wert wahr.

Funktion: boolean false()

Die Funktion false liefert den Wert falsch.

Anmerkung des Übersetzers:

XPath definiert keine Literale für wahr und falsch. Soll ein boolescher Wert als Parameter an eine Funktion oder ein benanntes XSLT-Template übergeben werden, muss dafür eine der Funktionen true oder false benutzt werden.

Funktion: boolean lang(string)

Die Funktion lang liefert einen Wert wahr oder falsch in Abhängigkeit davon, ob die durch xml:lang-Attribute angegebene Sprache des Kontextknotens die gleiche oder eine Untersprache der im Argument übergegebenen Zeichenkette ist. Die Sprache des Kontextknotens wird durch den Wert des Attributes xml:lang des Kontextknotens bestimmt oder, wenn der Kontextknoten kein Attribut xml:lang besitzt, durch den Wert des Attributes xml:lang beim nächsten Vorfahren des Kontextknotens, der ein Attribut xml:lang besitzt. Wenn es kein solches Attribut gibt, liefert lang den Wert falsch. Wenn es ein solches Attribut gibt, liefert lang den Wert wahr, wenn der Attributwert gleich dem Argument ist, unabhängig von der Groß- oder Kleinschreibung, oder wenn es ein mit - beginnendes Suffix derart gibt, dass der Attributwert gleich dem Argument ohne dieses Suffix ist, unabhängig von der Groß- oder Kleinschreibung. Beispielsweise würde lang("en") den Wert wahr liefern, wenn der Kontextknoten eines dieser fünf Elemente ist:

<para xml:lang="en"/>
<div xml:lang="en"><para/></div>
<para xml:lang="EN"/>
<para xml:lang="en-us"/>

Anmerkung des Übersetzers:

Handelt es sich beim Kontextknoten dagegen um das para-Element im Beispiel

<div xml:lang="en"><sect xml:lang="de"><para/></sect></div>

liefert lang("en") den Wert falsch. Der nächste Vorfahre mit einem xml:lang-Attribut ist in diesem Fall das Element sect, in welchem die Sprache auf de gesetzt wird.

Das Verhalten der Funktion lang darf nicht mit einem impliziten Vorhandensein des Attributs xml:lang verwechselt werden. Für das obige Beispiel liefert //para[@xml:lang='de'] eine leere Knotenmenge, während //para[lang('de')] das para-Element auswählt.

4.4 Zahlenfunktionen

Funktion: number number(object?)

Die Funktion number konvertiert ihr Argument in eine Zahl wie folgt:

Wird kein Argument übergeben, wird stattdessen eine Knotenmenge mit dem Kontextknoten als einzigem Element benutzt.

Anmerkung: Die Funktion number sollte nicht für die Konvertierung numerischer Daten in einem Element eines XML-Dokumentes benutzt werden, es sei denn, das Element ist von einem Typ, das numerische Daten in einem sprachunabhängigen Format repräsentiert (das typischerweise für die Präsentation für einen Anwender in ein sprachspezifisches Format umgewandelt würde). Darüber hinaus kann die Funktion number nur genutzt werden wenn das von dem Element genutzte sprachunabhängige Format mit der XPath-Syntax für Number konsistent ist.

Anmerkung des Übersetzers:

Insbesondere eignet sich eine Zahl im hiesigen Format (der Punkt zur Kennzeichnung der Tausenderstellen, das Komma zur Abgrenzung von den Dezimalstellen) nicht als Argument für die Funktion number. Der Aufruf von number('12.000,50') liefert beispielsweise den Wert NaN. Eine Umwandlung in das Format für Number kann in diesem Fall mit Hilfe der Funktion translate vorgenommen werden: number(translate('12.000,50', ',.', '.'))

Funktion: number sum(node-set)

Die Funktion sum liefert die Summe aller in eine Zahl konvertierten Zeichenkettenwerte der Knoten aus der Argumentknotenmenge.

Anmerkung des Übersetzers:

Sie eignet sich damit nur für Fälle, in denen die zu summierenden Werte direkt in der XML-Quelle vorliegen. Sollen die Summanden komplexer sein, d.h. jeweils durch einen eigenen Ausdruck berechnet werden, kann die Funktion sum nicht mehr benutzt werden. XPath nutzende Implementationen können aber eigene Sprachmittel bereitstellen, mit denen solche Berechnungen durchgeführt werden können.

Die Funktion sum hilft noch in einem anderen Anwendungsfall: aus der Definition des Verhaltens von number geht hervor, dass diese eine leere Knotenmenge in den Wert NaN konvertiert. Ein Ausdruck foo - bar liefert damit NaN, falls wenigstens eines der Elemente foo oder bar nicht existiert. Möchte man stattdessen, dass in diesem Fall die Zahl 0 für nichtexistierende Elemente angenommen wird, kann man dies über den Ausdruck sum(foo[1]) - sum(bar[1]) erreichen.

Funktion: number floor(number)

Die Funktion floor liefert die größte Zahl (die am nächsten an positiv unendlich liegt), die nicht größer als das Argument und ganzzahlig ist.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Absatz ergänzt werden:

Wenn das Argument NaN ist, wird NaN zurückgegeben. Wenn das Argument positiv unendlich ist, wird positiv unendlich zurückgegeben. Wenn das Argument negativ unendlich ist, wird negativ unendlich zurückgegeben. Wenn das Argument positiv null ist, wird positiv null zurückgegeben. Wenn das Argument negativ null ist, wird negativ null zurückgegeben. Wenn das Argument größer als null aber kleiner als 1 ist, wird positiv null zurückgegeben.

Funktion: number ceiling(number)

Die Funktion ceiling liefert die kleinste Zahl (die am nächsten an negativ unendlich liegt), die nicht kleiner als das Argument und ganzzahlig ist.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Absatz ergänzt werden:

Wenn das Argument NaN ist, wird NaN zurückgegeben. Wenn das Argument positiv unendlich ist, wird positiv unendlich zurückgegeben. Wenn das Argument negativ unendlich ist, wird negativ unendlich zurückgegeben. Wenn das Argument positiv null ist, wird positiv null zurückgegeben. Wenn das Argument negativ null ist, wird negativ null zurückgegeben. Wenn das Argument kleiner als null aber größer als -1 ist, wird positiv null zurückgegeben.

Funktion: number round(number)

Die Funktion round liefert die Zahl, die am nächsten am Argument liegt und die ganzzahlig ist. Wenn es zwei solche Zahlen gibt, wird die Zahl geliefert, die näher an positiv unendlich liegt. Ist das Argument NaN, wird NaN zurückgegeben. Ist das Argument positiv unendlich, wird positiv unendlich zurückgegeben. Ist das Argument negativ unendlich, wird negativ unendlich zurückgegeben. Ist das Argument positiv Null, wird positiv Null zurückgegeben. Ist das Argument negativ Null, wird negativ Null zurückgegeben. Ist das Argument kleiner als Null aber größer oder gleich -0.5, wird negativ Null zurückgegeben.

Anmerkung: In den letzten beiden Fällen ist das Ergebnis des Aufrufs der Funktion round verschieden von der Addition von 0.5 und dem Aufruf der Funktion floor.

Anmerkung des Übersetzers:

Davon kann man sich leicht selbst überzeugen:

Für -0 ergibt sich: floor(-0 + 0.5) = floor(0.5) = 0 (positiv Null)

Für -0.5 ergibt sich: floor(-0.5 + 0.5) = floor(0) = 0 (positiv Null)

5 Datenmodell

XPath operiert auf der Baumrepräsentation eines XML-Dokuments. Das folgende Kapitel beschreibt, wie XPath ein XML-Dokument als Baum modelliert. Dieses Modell ist rein konzeptionell und schreibt keinerlei spezielle Implementation vor. Die Beziehung zwischen diesem Modell und dem XML Information Set [XML Infoset] wird in [B Abbildung auf das XML Information Set] beschrieben.

Die durch XPath verarbeiteten XML-Dokumente müssen sich nach der XML Namensraum-Empfehlung [XML Names] richten.

Anmerkung des Übersetzers:

Insbesondere dürfen Namen von Elementen und Attributen das Zeichen »:« nur als Separator zwischen Namensraum-Präfix und lokalem Namen enthalten. Außerdem muss jedes benutzte Präfix deklariert worden sein. XML-Dokumente, die den Doppelpunkt nicht Namensraum-konform verwenden, können durch XPath-Implementationen nicht verarbeitet werden.

Der Baum enthält Knoten. Es gibt sieben Typen von Knoten:

Für jeden Knotentyp gibt es einen Weg, den Zeichenkettenwert eines Knotens dieses Typs zu bestimmen. Bei einigen Knotentypen ist der Zeichenkettenwert Teil des Knotens, bei anderen Knotentypen wird der Zeichenkettenwert aus den Zeichenkettenwerten der Nachkommen berechnet.

Anmerkung: Für Element- und Wurzelknoten ist der Zeichenkettenwert eines Knotens verschieden von der Zeichenkette, die von der DOM-Methode nodeValue zurückgegeben wird (siehe [DOM]).

Einige Knotentypen besitzen außerdem einen erweiterten Namen - ein Paar bestehend aus einem lokalen Teil und einem Namensraum-URI. Der lokale Teil ist eine Zeichenkette. Der Namensraum-URI ist entweder leer oder eine Zeichenkette. Der im XML-Dokument spezifizierte Namensraum-URI kann eine URI-Referenz sein, wie sie in [RFC2396] definiert ist; das bedeutet, sie kann einen Fragment-Bezeichner besitzen und sie kann relativ sein. Ein relativer URI sollte als absoluter URI während der Namensraum-Verarbeitung aufgelöst werden: die Namensraum-URIs der erweiterten Namen von Knoten im Datenmodell sollten absolut sein. Zwei erweiterte Namen sind gleich, wenn sie den gleichen lokalen Teil haben, und wenn beide einen leeren Namensraum-URI oder beide die gleichen, nichtleeren Namensraum-URIs besitzen.

Anmerkung des Übersetzers:

Nach einer Entscheidung des W3C-XML-Plenums ist die Behandlung relativer Namensraum-URIs implementationsabhängig. Gemäß Errata-Dokument [XPath Errata] müssen deshalb aus dem obigen Abschnitt die Sätze "Der im XML-Dokument spezifizierte Namensraum-URI kann eine URI-Referenz sein, wie sie in [RFC2396] definiert ist; das bedeutet, sie kann einen Fragment-Bezeichner besitzen und sie kann relativ sein. Ein relativer URI sollte als absoluter URI während der Namensraum-Verarbeitung aufgelöst werden: die Namensraum-URIs der erweiterten Namen von Knoten im Datenmodell sollten absolut sein." ersetzt werden durch:

Ein in einer Namensraum-Deklaration spezifierter Namensraum-Name in einem XML-Dokument ist eine URI-Referenz, wie sie in [RFC2396] definiert ist; das bedeutet sie kann einen Fragment-Bezeichner besitzen und sie kann relativ sein. Die Namensraum-URI-Komponente eines erweiterten Namens ist implementationsabhängig, wenn der erweiterte Name aus einem QName expandiert wird, dessen Präfix durch eine Namensraum-Deklaration mit einem relativen URI (mit oder ohne Fragment-Bezeichner) als Namensraum-Namen deklariert wurde. Ein XPath-Ausdruck, der vom Wert der Namensraum-URI-Komponente eines solchen erweiterten Namens abhängt, ist nicht interoperabel.

Relative URIs der Form »host.example.org/namespace« (fehlendes Schema), »home/schema« (fehlende Hostangabe), »http://www.w3.org/1999/../2001/XMLSchema« (mit speziellen Pfadkomponenten) oder »http://www.schema.org/address#one« (mit Fragment-Bezeichner) sollten damit vermieden werden.

Es existiert eine Ordnung, Dokumentordnung, die für alle Knoten im Dokument definiert ist und die zu der Ordnung korrespondiert, in der die ersten Zeichen der XML-Repräsentation aller Knoten in der XML-Repräsentation des Dokumentes nach der Expandierung allgemeiner Entities stehen. Der Wurzelknoten ist demzufolge der erste Knoten. Elementknoten stehen vor ihren Kindern. Das bedeutet, die Dokumentordnung ordnet Elementknoten in der Reihenfolge ihrer Start-Tags im XML-Dokument (nach der Expandierung von Entities). Attribut- und Namensraum-Knoten eines Elementes kommen vor den Kindern des Elementes. Namensraum-Knoten erscheinen per Definition vor den Attributknoten. Die relative Ordnung innerhalb der Namensraum-Knoten ist implementationsabhängig. Die relative Ordnung innerhalb der Attributknoten ist implementationsabhängig. Die umgekehrte Dokumentordnung ist die Umkehrung der Dokumentordnung.

Anmerkung des Übersetzers:

Damit ist für Attribut- und Namensraum-Knoten die Reihenfolge der Repräsentation im XML-Dokument unerheblich.

Man darf an dieser Stelle nicht vergessen, dass die Elemente einer Knotenmenge trotzdem immer ungeordnet sind. Die Eigenschaft, die Knoten einer Menge in einer bestimmten Reihenfolge zu betrachten, gehört immer zu einer Operation oder Funktion, die auf dieser Menge ausgeführt wird. So konvertieren die Funktionen string, boolean und number bei einer gegebenen Knotenmenge immer den ersten Knoten bezüglich der Dokumentordnung. Entsprechend legen auf Ausdrücke angewandte Prädikate immer die Dokumentordnung zugrunde. Demgegenüber legt innerhalb eines Lokalisierungsschrittes immer die jeweilige Achse die für die dazugehörenden Prädikate relevante Ordnung fest. Nachdem eine Knotenmenge konstruiert wurde, ist sie (wieder) ungeordnet. Siehe dazu auch die entsprechende Anmerkung in Kapitel [3.3 Knotenmengen].

Wurzel- und Elementknoten besitzen eine geordnete Liste von Kindknoten. Mehrere Knoten haben niemals gemeinsame Kinder: wenn ein Knoten von einem anderen Knoten verschieden ist, dann ist kein Kindknoten des einen Knotens mit einem der Kindknoten des anderen Knotens identisch. Jeder Knoten mit Ausnahme des Wurzelknotens besitzt genau einen Elternknoten, wobei dieser entweder ein Elementknoten oder der Wurzelknoten ist. Ein Wurzel- oder ein Elementknoten ist der Elternknoten jedes seiner Kindknoten. Die Nachkommen eines Knotens sind die Kinder des Knotens sowie die Nachkommen der Kinder des Knotens.

Anmerkung des Übersetzers:

Die Bezeichnungen Eltern- und Kindknoten sind vielleicht nicht ganz glücklich. Jeder Knoten besitzt nämlich maximal einen Elternknoten. Daneben sind Attribut- und Namensraum-Knoten vergleichbar mit rebellierenden Teenagern, die im XPath-Datenmodell nicht als Kinder ihrer Element-Elternknoten betrachtet werden.

5.1 Wurzelknoten

Der Wurzelknoten ist die Wurzel des Baumes. Ein Wurzelknoten kommt nur als Wurzel des Baumes vor. Der Elementknoten für das Dokument-Element ist ein Kind des Wurzelknotens. Der Wurzelknoten hat als Kinder ebenfalls Processing-Instruction-Knoten und Kommentarknoten für Processing Instructions und Kommentare, die im Prolog oder hinter dem Ende des Dokument-Elementes auftreten.

Anmerkung des Übersetzers:

Die Dokumenttyp-Deklaration ist kein Kind des Wurzelknotens. Sie kommt als solches an keiner Stelle im XPath-Datenmodell vor. So kann ein XSLT-Stylesheet keine Kopie der Dokumenttyp-Deklaration erzeugen. Ebenso werden innerhalb der Dokumenttyp-Deklaration auftretende Kommentare oder Processing Instructions nicht durch XPath-Knoten repräsentiert.

Der Zeichenkettenwert des Wurzelknotens ergibt sich aus der Verkettung der Zeichenkettenwerte aller Textknoten in Dokumentordnung, die Nachkommen des Wurzelknotens sind.

Anmerkung des Übersetzers:

Da außerhalb des Dokument-Elementes keine Textknoten auftreten dürfen, gilt also

string(/) = string(/*)

oder mit anderen Worten: Der Wurzelknoten und sein (einziger) Element-Kindknoten besitzen den gleichen Zeichenkettenwert. Diesen erhält man auch, wenn aus dem Eingabedokument jegliches Markup entfernt und nur die Zeichendaten behalten werden.

Zum Vergleich: Im Document Object Model [DOM] ist der Wert des vergleichbaren Attributs nodeValue für ein Document-Objekt dagegen die leere Zeichenkette.

Der Wurzelknoten hat keinen erweiterten Namen.

Anmerkung des Übersetzers:

Das bedeutet, dass die Funktionen name, local-name und namespace-uri als Ergebnis die leere Zeichenkette liefern. Das in DOM definierte Attribut nodeName besitzt dagegen für das Document-Objekt als Wert die Zeichenkette »#document«.

5.2 Elementknoten

Für jedes Element im Dokument gibt es einen Elementknoten. Ein Elementknoten besitzt einen erweiterten Namen, der sich durch Expandierung des im Tag des Elementes spezifierten QName in Übereinstimmung mit der XML-Namensraum-Empfehlung [XML Names] ergibt. Der Namensraum-URI des erweiterten Namen des Elementes ist leer, wenn der QName kein Präfix enthält und es keinen anwendbaren voreingestellten Namensraum gibt.

Anmerkung: In der im Anhang A.3 von [XML Names] verwendeten Notation entspricht der lokale Teil des erweiterten Namens dem Attribut type des Elementes ExpEType; der Namensraum-URI des erweiterten Namens entspricht dem Attribut ns des Elementes ExpEType. Letzterer ist leer, wenn das Attribut ns des Elementes ExpEType weggelassen wurde.

Die Kinder eines Elementknotens sind die enthaltenen Elementknoten, Kommentarknoten, Processing-Instruction-Knoten und Textknoten. Entity-Referenzen zu internen und externen Entities werden expandiert. Zeichenreferenzen werden aufgelöst.

Der Zeichenkettenwert eines Elementknotens ergibt sich aus der Verkettung der Zeichenkettenwerte aller Textknoten, die Nachkommen des Elementknotens in Dokumentordnung sind.

Anmerkung des Übersetzers:

Damit gilt, dass der Zeichenkettenwert eines Elementknotens genauso als Verkettung der Zeichenkettenwerte seiner Element- und Textkinder in Dokumentordnung aufgefasst werden kann.

Zum Vergleich: Im Document Object Model [DOM] ist dagegen der Wert des vergleichbaren Attributs nodeValue für ein Element-Objekt die leere Zeichenkette.

5.2.1 Eindeutige IDs

Ein Elementknoten kann einen eindeutigen Bezeichner (ID) besitzen. Dies ist der Wert des Attributes, das in der DTD mit dem Typ ID deklariert wurde. Keine zwei Elemente in einem Dokument dürfen den gleichen eindeutigen Bezeichner besitzen. Falls ein XML-Prozessor zwei Elemente in einem Dokument mit dem gleichen eindeutigen Bezeichner meldet (was nur möglich ist, wenn das Dokument ungültig ist), dann muss das zweite Element in Dokumentordnung so behandelt werden, als habe es keinen eindeutigen Bezeichner.

Anmerkung: Wenn ein Dokument keine DTD besitzt, dann hat kein Element des Dokumentes einen eindeutigen Bezeichner.

Anmerkung des Übersetzers:

Für zwei oder mehr Elemente mit dem gleichen eindeutigen Bezeichner liefert die Funktion id nur den ersten Elementknoten in Dokumentordnung zurück. Da die Eigenschaft eines Attributes, eindeutiger Bezeichner zu sein, in der DTD deklariert wird, kann ohne DTD dieses Attribut nicht mehr erkannt werden. Das bedeutet, dass die Funktion id nach dem Entfernen der DTD aus dem Eingabedokument für jedes Argument nur noch die leere Knotenmenge liefert. Dies ist einer der wenigen Fälle, in denen die Existenz einer DTD sich auf die Auswertung eines XPath-Ausdrucks auswirkt.

5.3 Attributknoten

Jedes Element besitzt eine mit ihm verbundene Menge von Attributknoten; das Element ist der Elternknoten jedes dieser Attributknoten. Allerdings ist ein Attributknoten kein Kind seines Elternknotens.

Anmerkung: Dies unterscheidet sich vom DOM, welches ein Element nicht als Elternknoten seiner Attribute behandelt (siehe [DOM]).

Mehrere Elemente haben niemals gemeinsame Attributknoten: wenn ein Elementknoten verschieden von einem anderen Elementknoten ist, dann ist kein Attributknoten des einen Elementknotens mit einem der Attributknoten eines anderen Elementknotens identisch.

Anmerkung: Der Operator = testet, ob zwei Knoten den gleichen Wert haben, nicht ob es dieselben Knoten sind. Vergleicht man die Attribute von zwei verschiedenen Elementen mittels =, so kann sich Gleichheit ergeben, obwohl diese nicht dieselben Knoten sind.

Anmerkung des Übersetzers:

Wert bedeutet hier wieder Zeichenkettenwert. Tatsächlich gilt die obige Anmerkung für alle Knoten, nicht nur für Attribute. Um die Identität zweier Knoten zu überprüfen, kann man sich beispielsweise der in Kapitel [3.3 Knotenmengen] im Zusammenhang mit dem Operator | vorgestellten Technik bedienen.

Ein vorgegebenes Attribut wird genauso behandelt wie ein spezifiziertes Attribut. Falls für einen Elementtyp ein Attribut in der DTD deklariert wurde, der Vorgabewert jedoch als #IMPLIED deklariert wurde und das Attribut für das Element nicht angegeben wurde, so enthält die Attributmenge des Elements keinen Knoten für dieses Attribut.

Anmerkung des Übersetzers:

Beispiel:

<!DOCTYPE see [
<!ELEMENT see EMPTY>
<!ATTLIST see access (public|restricted) "public"
              ref    CDATA               #IMPLIED >
]>
<see />

In diesem Fall besitzt der einzige Elementknoten see im XPath-Datenmodell genau einen Attributknoten namens access mit dem Wert public. Im Gegensatz zu ref handelt es sich bei access um ein vorgegebenes Attribut.

Das XPath-Datenmodell liefert keinerlei Informationen darüber, ob ein solches Attribut im Start-Tag eines Elements spezifiziert wurde oder nicht. In zweitem Fall ändert sich im Falle des Entfernens der DTD die Baumrepräsentation des XML-Dokumentes, da alle vorgegebenen, aber nicht spezifizierten Attribute wegfallen.

Einige Attribute, wie xml:lang und xml:space, besitzen die Semantik, dass sie für alle Elemente gelten, die Nachkommen des Elementes sind, das das Attribut trägt, es sei denn sie wurden in einer Instanz eines Nachkommen-Elementes durch das gleiche Attribut überschrieben. Das wirkt sich allerdings nicht darauf aus, wo Attributknoten im Baum vorkommen: ein Element besitzt nur Attributknoten für die Attribute, die explizit im Start-Tag oder Leeres-Element-Tag dieses Elements angegeben wurden, oder die in der DTD explizit mit einem Vorgabewert deklariert wurden.

Anmerkung des Übersetzers:

Im Zusammenhang mit der Funktion lang wurde auf diese Eigenschaft bereits hingewiesen. Ein Attribut xml:lang wirkt sich zwar semantisch auf die Nachkommen aus, allerdings erscheint es nicht implizit als Attributknoten bei diesen Nachkommen.

Damit liefert z.B. //*[lang('de')] in der Regel eine andere Knotenmenge als //*[@xml:lang='de']. Im ersten Ausdruck werden alle die Knoten ausgewählt, für die selbst oder für deren nächsten Vorfahren die Sprache Deutsch (de) festgelegt wurde. Der zweite Ausdruck wählt dagegen nur die Knoten aus, die ein Attribut xml:lang explizit oder als Vorgabewert mit dem Wert de besitzen. Abgesehen davon würde die zweite Variante auch Attribute wie xml:lang="DE-CH" unberücksichtigt lassen.

Ein Attributknoten hat einen erweiterten Namen und einen Zeichenkettenwert. Der erweiterte Name wird durch Expandierung des im Tag im XML-Dokument angegebenen QName in Übereinstimmung mit der XML-Namensraum-Empfehlung [XML Names] berechnet. Der Namensraum-URI des Attributnamens ist leer, falls der QName des Attributs kein Präfix enthält.

Anmerkung des Übersetzers:

Entsprechend der XML-Namensraum-Empfehlung [XML Names] wirkt sich somit ein voreingestellter Namensraum im Gegensatz zu Elementknoten nicht auf Attribute ohne Präfix aus.

Anmerkung: In der im Anhang A.3 von [XML Names] verwendeten Notation entspricht der lokale Teil des erweiterten Namens dem Attribut name des Elementes ExpAName; der Namensraum-URI des erweiterten Namens entspricht den Attribut ns des Elementes ExpAName. Letzterer ist leer, wenn das Attribut ns des Elementes ExpAName weggelassen wurde.

Ein Attributknoten besitzt einen Zeichenkettenwert. Dieser Zeichenkettenwert ist der durch die XML-Empfehlung [XML] spezifizierte normalisierte Wert. Ein Attribut, dessen normalisierter Wert eine Zeichenkette der Länge null ist, wird nicht gesondert behandelt: es resultiert in einem Attributknoten, dessen Zeichenkettenwert eine Zeichenkette der Länge null ist.

Anmerkung des Übersetzers:

Normalisierung bedeutet, dass alle Entity- und Zeichenreferenzen aufgelöst sowie alle Leerraumzeichen durch die gleiche Anzahl Leerzeichen ersetzt werden. Ist der Attributtyp nicht CDATA, wird der Attributwert darüber hinaus wie bei der Anwendung der Funktion normalize-space umgewandelt.

Anmerkung: Es ist möglich, dass Attribute mit Vorgabewerten in einer externen DTD oder einem externen Parameter-Entity deklariert werden. Die XML-Empfehlung verlangt nicht, dass ein XML-Prozessor eine externe DTD oder ein externes Parameter-Entity einliest, es sei denn dieser ist validierend. Ein Stylesheet oder ein anderes Werkzeug, das annimmt, der XPath-Baum enthalte in einer externen DTD oder einem externen Parameter-Entity deklarierte Vorgabewerte, kann möglicherweise mit nicht-validierenden XML-Prozessoren nicht funktionieren.

Es gibt keine Attributknoten zu Attributen, die Namensräume deklarieren (siehe [XML Names]).

Anmerkung des Übersetzers:

Attribute mit dem Namen »xmlns« oder dem Präfix »xmlns« werden nicht als Attributknoten sondern als Namensraum-Knoten im Datenmodell repräsentiert.

5.4 Namensraum-Knoten

Jedem Element ist eine Menge von Namensraum-Knoten zugeordnet, einer für jedes einzelne Namensraum-Präfix, der für das Element gültig ist (einschließlich des Präfix xml, das implizit durch die XML-Namensraum-Empfehlung deklariert wird) und einer für den voreingestellten Namensraum, falls einer für das Element gültig ist. Das Element ist der Elternknoten jedes dieser Namensraum-Knoten; ein Namensraum-Knoten ist allerdings kein Kind seines Elternelementes. Mehrere Elemente haben niemals gemeinsame Namensraum-Knoten: wenn ein Elementknoten verschieden von einem anderen Elementknoten ist, dann ist kein Namensraum-Knoten des einen Elementknotens mit einem der Namensraum-Knoten eines anderen Elementknotens identisch. Das bedeutet, ein Element besitzt einen Namensraum-Knoten:

Anmerkung des Übersetzers:

Namensraum-Deklarationen wirken sich damit in der Regel auf die Nachkommen des Elementes aus, in dem diese Deklaration erscheint. Im Gegensatz zu den Attributen xml:lang und xml:space werden Namensraum-Knoten jedoch tatsächlich an die Nachkommen vererbt. Jeder Elementknoten besitzt ein eigenes Knoten-Exemplar für jeden gültigen Namensraum.

Wie bereits in Kapitel [1 Einleitung] an einem Beispiel verdeutlicht wurde, folgt aus der Namensraum-Empfehlung, dass jedes Element wenigstens einen Namensraum-Knoten mit dem Präfix xml und dem Namensraum-URI http://www.w3.org/XML/1998/namespace besitzt.

Da das XPath-Datenmodell keine Informationen darüber enthält, an welchen Stellen Namensraum-Deklarationen im Dokument auftreten, besitzen die Beispiele

<foo:e1 xmlns:foo="bar"><foo:e2 /></foo:e1>

und

<foo:e1 xmlns:foo="bar"><foo:e2 xmlns:foo="bar" /></foo:e1>

die gleiche Baumrepräsentation.

Ein Namensraum-Knoten besitzt einen erweiterten Namen: der lokale Teil ist das Namensraum-Präfix (dieser ist leer, falls der Namensraum-Knoten den voreingestellten Namensraum repräsentiert); der Namensraum-URI ist immer leer.

Der Zeichenkettenwert eines Namensraum-Knotens ist der Namensraum-URI, der an das Namensraum-Präfix gebunden ist; wenn dieser relativ ist, muss er wie ein Namensraum-URI in einem erweiterten Namen aufgelöst werden.

Anmerkung des Übersetzers:

Nach einer Entscheidung des W3C-XML-Plenums ist die Behandlung relativer Namensraum-URIs implementationsabhängig. Gemäß Errata-Dokument [XPath Errata] muss dieser letzte Absatz durch den folgenden ersetzt werden:

Der Zeichenkettenwert eines Namensraum-Knotens ist der Namensraum-URI, der an das Namensraum-Präfix gebunden ist; wenn der in der Namensraum-Deklaration auftretende Namensraum-Name ein relativer URI (mit oder ohne Fragment-Bezeichner) ist, so ist der Zeichenkettenwert implementationsabhängig. Ein XPath-Ausdruck, der vom Zeichenkettenwert eines solchen Namensraum-Knotens abhängt, ist nicht interoperabel.

Die Definition des erweiterten Namens für Namensraum-Knoten mag auf den ersten Blick etwas ungewöhnlich erscheinen. Tatsächlich wurde hier das Namensraum-Präfix als eigentlich relevanter Namensbestandteil dem Schema für erweiterte Namen angepasst, den jeder Knoten besitzt. Der Namensraum-URI des Namens ist leer, da der Name eines Namensraum-Knotens nicht von anderen gültigen Namensraum-Deklarationen abhängt.

Zur Illustration zwei Beispiele: die Deklaration xmlns:prefix="urn:eindeutiger-bezeichner" erzeugt einen Namensraum-Knoten, dessen erweiterter Name gleich [»prefix«, »«] ist. Eine Deklaration für den voreingestellten Namensraum xmlns="urn:eindeutiger-bezeichner" führt zu einem Knoten mit dem erweiterten Namen [»«, »«]. Der Zeichenkettenwert ist in beiden Fällen »urn:eindeutiger-bezeichner«. Ein Namensraum-Knoten hat niemals einen leeren Zeichenkettenwert.

Namensraum-Knoten werden benötigt, wenn in den Daten enthaltene qualifizierte Namen ausgewertet werden sollen. Die Typangabe in einem XML-Schema ist so ein Beispiel: type="ob:adresse". Zur Ermittlung des dazugehörigen Namensraum-URIs kann folgender Ausdruck verwendet werden:

string(namespace::*[name()=substring-before(../@type,':')])

Da der Namensraum-Knoten für den voreingestellten Namensraum einen leeren Namen besitzt und daher nicht direkt als Knotentest angegeben werden kann, lässt sich ein solcher Knoten nur mit Hilfe eines geeigneten Prädikats auswählen:

namespace::*[name()='']

5.5 Processing-Instruction-Knoten

Für jede Processing Instruction gibt es einen Processing-Instruction-Knoten, mit Ausnahme der Processing Instructions, die innerhalb der Dokumenttyp-Deklaration erscheinen.

Eine Processing Instruction besitzt einen erweiterten Namen: der lokale Teil ist das Ziel der Processing Instruction; der Namensraum-URI ist leer. Der Zeichenkettenwert eines Processing-Instruction-Knotens ist der Teil der Processing Instruction, der dem Ziel und allem Leerraum folgt. Dieser beinhalt nicht das abschließende ?>.

Anmerkung des Übersetzers:

Die folgende Processing Instruction

<?xml-stylesheet href='style.xsl' title='Hauptstylesheet'?>

wird z.B. durch einen Knoten repräsentiert, dessen erweiterter Namexml-stylesheet«, »«] und dessen Zeichenkettenwert »href='style.xsl' title='Hauptstylesheet'« ist.

Die Abschnitte, die hier wie Attribute einer Processing Instruction aussehen (href und title), sind in Wirklichkeit nur Teile des Inhalts, also des Zeichenkettenwerts. Durch XPath werden an dieser Stelle keine Attributknoten bereitgestellt. Möchte man auf diese Pseudo-Attribute zugreifen, muss man sich mit den Funktionen für Zeichenketten behelfen.

Namensraum-Deklarationen wirken sich nicht auf Processing Instructions aus.

Anmerkung: Die XML-Deklaration ist keine Processing Instruction. Daher gibt es auch keinen Processing-Instruction-Knoten für die XML-Deklaration.

Anmerkung des Übersetzers:

Es ist nicht möglich, auf die Angaben innerhalb der XML-Deklaration zuzugreifen. Die Versionsnummer und die Kodierungsangabe gehören nicht zum XPath-Datenmodell.

5.6 Kommentarknoten

Für jeden Kommentar gibt es einen Kommentarknoten, mit Ausnahme der Kommentare, die innerhalb der Dokumenttyp-Deklaration erscheinen.

Der Zeichenkettenwert eines Kommentarknotens ist der Inhalt des Kommentars ohne die öffnenden Zeichen <!-- und die schließenden Zeichen -->.

Ein Kommentarknoten besitzt keinen erweiterten Namen.

Anmerkung des Übersetzers:

Das bedeutet, dass die Funktionen name, local-name und namespace-uri als Ergebnis die leere Zeichenkette liefern. Das in DOM definierte Attribut nodeName besitzt dagegen für ein Comment-Objekt als Wert die Zeichenkette »#comment«.

5.7 Textknoten

Zeichendaten werden in Textknoten zusammengefasst. Dabei werden so viele Zeichen wie möglich in jedem Textknoten zusammengefasst: ein Textknoten hat niemals als direkten Vorgänger oder Nachfolger einen anderen Textknoten. Der Zeichenkettenwert eines Textknotens besteht aus den Zeichendaten. Ein Textknoten enthält immer wenigstens ein Zeichen.

Jedes Zeichen innerhalb eines CDATA-Abschnittes wird wie Zeichendaten behandelt. So wird <![CDATA[<]]> im Quelldokument genauso behandelt wie &lt;. Beides ergibt das einzelne Zeichen < in einem Textknoten innerhalb des Baumes. Ein CDATA-Abschnitt wird damit so behandelt, als würden <![CDATA[ und ]]> entfernt und jedes Vorkommen von < und & durch &lt; beziehungsweise &amp; ersetzt werden.

Anmerkung des Übersetzers:

Das XPath-Datenmodell enthält also keinerlei Informationen darüber, in welcher Form ein Zeichen innerhalb des XML-Dokumentes repräsentiert war. Die folgenden Textinhalte des Elementes x werden alle auf den gleichen Textknoten mit dem Inhalt »A« abgebildet:

<x>A</x>
<x><![CDATA[A]]></x>
<x>&#65;</x>
<x>&#x0041;</x>

Entsprechend würde beispielsweise der Inhalt des folgenden Elementes para in einem einzigen Textknoten zusammengefasst werden. Der Beginn des CDATA-Abschnittes kann in XPath nicht bestimmt werden. Das Document Object Model [DOM] sieht hier stattdessen spezielle Objekte Text und CDATASection vor.

<para>
   Hier folgen Beispiel &amp; Erklärung:
   <![CDATA[a > 10 and a < 20]]> bedeutet ...
</para>

Einzelne Zeichendaten werden innerhalb des Datenmodells nicht separat repräsentiert. Zur Verarbeitung muss deshalb auf die bereitgestellten Zeichenkettenfunktionen zurückgegriffen werden.

Anmerkung: Wird ein Textknoten, der das Zeichen < enthält, als XML ausgegeben, so muss das Zeichen < geschützt werden, beispielsweise durch &lt; oder durch Einschluss in einen CDATA-Abschnitt.

Zeichen innerhalb von Kommentaren, Processing Instructions und Attributwerten erzeugen keine Textknoten. Zeilenenden in externen Entities werden zu #xA normalisiert, so wie in der XML-Empfehlung [XML] spezifiziert.

Anmerkung des Übersetzers:

Gemäß Errata-Dokument [XPath Errata] muss an dieser Stelle folgender Satz eingefügt werden:

Leerraum außerhalb des Dokument-Elementes erzeugt keine Textknoten.

Genau genommen lässt sich durch XPath nicht beeinflussen, ob Leerraum generell Textknoten erzeugen soll. Abhängig von der Applikation, die XPath verwendet, werden für ausschließlich aus Leerraum bestehende Bereiche Textknoten angelegt oder nicht. Die Illustration zum Beispiel in Kapitel [1 Einleitung] beruht auf der Annahme, dass solche Leerraum-Textknoten vorhanden sind. Das ist auch das Standardverhalten in XSLT [XSLT] für zu verarbeitende XML-Dokumente. Durch Verwendung der XSLT-Elemente xsl:strip-space und xsl:preserve-space lässt sich dieses Verhalten allerdings beeinflussen. Darüberhinaus werden Leerraum-Textknoten, die als Kind eines Elementes mit xml:space="preserve" (siehe [XML, 2nd Edition]) auftreten, niemals entfernt.

Die Existenz solcher Leerraum-Textknoten kann sich auf Kontextgröße und -position und damit auf das Ergebnis der Funktionen last, position und count auswirken. Die Berechnung des Ausdrucks name/text()[1] für das folgende Beispiel hängt entscheidend davon ab, ob Leerraum-Textknoten mitgezählt werden oder nicht:

<name>
   <anrede>Herr</anrede> Müller-Lüdenscheidt
</name>

Ein Textknoten besitzt keinen erweiterten Namen.

Anmerkung des Übersetzers:

Das bedeutet, dass die Funktionen name, local-name und namespace-uri als Ergebnis die leere Zeichenkette liefern. Das in DOM definierte Attribut nodeName besitzt dagegen für Text-Objekte als Wert die Zeichenkette »#text« und für CDATASection-Objekte den Wert »#cdata-section«.

6 Konformität

XPath ist in erster Linie als Komponente gedacht, die von anderen Spezifikationen genutzt werden kann. Demzufolge verlässt sich XPath auf Spezifikationen, die XPath nutzen (etwa [XPointer] und [XSLT]), Kriterien für die Konformität von XPath zu spezifizieren und definiert selbst keinerlei Konformitätskriterien für unabhängige XPath-Implementationen.

Anmerkung des Übersetzers:

Die Organisation Oasis hat eine Kommission für die Konformität von XSLT- und XPath-Implementationen [XSLT Konformität] gebildet, die geeignete Szenarien für eine Test-Suite zusammenstellt.


A Referenzen

A.1 Normative Referenzen

IEEE 754
Institute of Electrical and Electronics Engineers. IEEE Standard for Binary Floating-Point Arithmetic. ANSI/IEEE Std 754-1985.
RFC2396
T. Berners-Lee, R. Fielding, and L. Masinter. Uniform Resource Identifiers (URI): Generic Syntax. IETF RFC 2396. Siehe http://www.ietf.org/rfc/rfc2396.txt.
XML
World Wide Web Consortium. Extensible Markup Language (XML) 1.0. W3C Recommendation. Siehe http://www.w3.org/TR/1998/REC-xml-19980210
XML Names
World Wide Web Consortium. Namespaces in XML. W3C Recommendation. Siehe http://www.w3.org/TR/REC-xml-names

A.2 Andere Referenzen

Character Model
World Wide Web Consortium. Character Model for the World Wide Web. W3C Working Draft. Siehe http://www.w3.org/TR/WD-charmod
DOM
World Wide Web Consortium. Document Object Model (DOM) Level 1 Specification. W3C Recommendation. Siehe http://www.w3.org/TR/REC-DOM-Level-1
JLS
J. Gosling, B. Joy, and G. Steele. The Java Language Specification. Siehe http://java.sun.com/docs/books/jls/index.html.
ISO/IEC 10646
ISO (International Organization for Standardization). ISO/IEC 10646-1:1993, Information technology -- Universal Multiple-Octet Coded Character Set (UCS) -- Part 1: Architecture and Basic Multilingual Plane. International Standard. Siehe http://www.iso.ch/cate/d18741.html.
TEI
C.M. Sperberg-McQueen, L. Burnard Guidelines for Electronic Text Encoding and Interchange. Siehe http://etext.virginia.edu/TEI.html.
Unicode
Unicode Consortium. The Unicode Standard. Siehe http://www.unicode.org/unicode/standard/standard.html.
XML Infoset
World Wide Web Consortium. XML Information Set. W3C Working Draft. Siehe http://www.w3.org/TR/xml-infoset
XPointer
World Wide Web Consortium. XML Pointer Language (XPointer). W3C Working Draft. Siehe http://www.w3.org/TR/WD-xptr
XQL
J. Robie, J. Lapp, D. Schach. XML Query Language (XQL). Siehe http://www.w3.org/TandS/QL/QL98/pp/xql.html
XSLT
World Wide Web Consortium. XSL Transformations (XSLT). W3C Recommendation. Siehe http://www.w3.org/TR/xslt

B Abbildung auf das XML Information Set (nicht normativ)

Die Knoten im XPath-Datenmodell lassen sich aus den durch das XML Information Set [XML Infoset] bereitgestellten Informationseinheiten wie folgt ableiten.

Anmerkung: Eine neue Version des XML Information Set Arbeitsentwurfs, die die Version vom 17. Mai ersetzen wird, war zu der Zeit als die Vorbereitung dieser Version der XPath-Spezifikation vollendet wurde, kurz vor der Fertigstellung. Ihre Veröffentlichung wurde zur gleichen Zeit oder kurz nach Veröffentlichung dieser Version von XPath erwartet. Die Abbildung wird für diese neue Version des XML Information Set Arbeitsentwurfs angegeben. Falls die neue Version des XML Information Set Arbeitsentwurfs noch nicht veröffentlicht worden sein sollte, so können W3C-Mitglieder die interne Arbeitsgruppenversion http://www.w3.org/XML/Group/1999/09/WD-xml-infoset-19990915.html (nur für Mitglieder) einsehen.

Anmerkung des Übersetzers:

Das XML Information Set beschreibt die aus einem XML-Dokument ableitbaren Informationen auf einer abstrakten Ebene. Zu diesem Zweck wurden elf Typen, sogenannte Informationseinheiten (information items) definiert. Jede dieser Informationseinheiten besitzt eine Reihe von Eigenschaften (properties). Es wurde im XML Information Set bewusst nicht der Term "Knoten" verwendet, um Verwechslungen mit DOM- und XPath-Knoten zu vermeiden. Die im XPath-Datenmodell definierten Knotentypen beschreiben eine Teilmenge der im XML Information Set verfügbaren Informationen und lassen sich daher aus diesen Informationseinheiten ableiten.

Zum Zeitpunkt der Erstellung dieser Übersetzung stand das XML Information Set kurz vor seiner Verabschiedung als Empfehlung. Im Vergleich zu der hier angesprochenen Version vom Dezember 1999 haben sich einige Details geändert. Die sich daraus ergebenden Änderungen bei der Abbildung des XPath-Datenmodells werden im folgenden in den jeweiligen Anmerkungen angegeben.


Zusätzliche Referenzen der deutschen Übersetzung

XML, 2nd Edition
World Wide Web Consortium. Extensible Markup Language (XML) 1.0 (Second Edition). W3C Recommendation. Siehe http://www.w3.org/TR/2000/REC-xml-20001006
ISO/IEC 10646, 2nd Edition
ISO (International Organization for Standardization). ISO/IEC 10646-1:2000, Information technology -- Universal Multiple-Octet Coded Character Set (UCS) -- Part 1: Architecture and Basic Multilingual Plane, Edition: 2 (Monolingual). International Standard. Siehe http://www.iso.ch/cate/d29819.html.
XSLT Konformität
Oasis (Organization for the Advancement of Structured Information Standards). Oasis XSLT/XPath Conformance Subcommittee. Siehe http://www.oasis-open.org/committees/xslt/.
XPath Errata
World Wide Web Consortium. XML Path Language (XPath) Version 1.0 Specification Errata. 29.09.2000. Siehe http://www.w3.org/1999/11/REC-xpath-19991116-errata.
XPath Requirements 2.0
World Wide Web Consortium. XPath Requirements Version 2.0. W3C Working Draft. Siehe http://www.w3.org/TR/xpath20req.
XQuery
World Wide Web Consortium. XQuery: A Query Language for XML. W3C Working Draft. Siehe http://www.w3.org/TR/xquery.
XSLT 1.1
World Wide Web Consortium. XSL Transformations (XSLT) Version 1.1. W3C Working Draft. Siehe http://www.w3.org/TR/xslt11/.