XPath-Tutorial für Einsteiger

Mit der Verbreitung von XML als Auszeichnungssprache für den plattformunabhängigen Austausch von Daten stieg der Bedarf nach einem Standard, der es nicht auf XML basierenden Anwendungen ermöglicht, komplexe Abfragen an XML-Dokumente zu stellen.

Hinweis

Die Extensible Markup Language (kurz XML) ist eine Auszeichnungssprache, die der Darstellung hierarchisch strukturierter Daten in Textform dient. XML ist für Mensch und Maschine gleichermaßen gut lesbar und wird u. a. im World Wide Web zum Datenaustausch zwischen zwei Computersystemen verwendet.

Entsprechende Standards für den programmgesteuerten Zugriff auf XML-Dokumente wurden vom W3-Konsortium mit XQuery und XSLT entwickelt. Diese halten Programmierschnittstellen bereit, über die Anwendungen auf XML-Dokumente zugreifen, Inhalte abfragen oder XML-Dokumente transformieren können. Voraussetzung dafür ist ein Standard, der die Adressierung von Elementen in XML-Dokumenten ermöglicht: die Pfadbeschreibungssprache XPath.

Wir führen Sie in das XPath-Datenmodell (XDM) ein und stellen Ihnen die Syntax vor, die XPath-Ausdrücken zur Lokalisierung von XML-Elementen zugrunde liegt.

Domain kaufen
Registrieren Sie Ihre perfekte Domain
  • Inklusive Wildcard-SSL-Zertifikat
  • Inklusive Domain Lock
  • Inklusive 2 GB E-Mail-Postfach

Was ist XPath?

Bei der XML Path Language (XPath) handelt es sich um eine vom W3-Konsortium entwickelte Pfadbeschreibungssprache für XML-Dokumente. XPath stellt Anwendern eine nicht XML-basierte Syntax zur Verfügung, die es ermöglicht, die Elemente eines XML-Dokuments gezielt zu adressieren.

In der Regel kommt XPath eingebettet in eine Wirtssprache (Host Language) zum Einsatz, die eine Verarbeitung der adressierten XML-Elemente ermöglicht. XQuery beispielsweise dient der Abfrage von per XPath adressierten XML-Elementen. XSLT bedient sich der Abfragesprache bei der Transformation von XML-Dokumenten.

  • XPath: Navigation in XML-Dokumenten
  • XQuery: Abfragen auf XML-Dokumenten
  • XSLT: Transformation von XML-Dokumenten

Die aktuelle Version XPath 3.1 ist in der W3C-Recommendation vom 21. März 2017 spezifiziert.

Hinweis

Trotz Weiterentwicklung unterstützen zahlreiche XSLT-Prozessoren, Webbrowser und Anwendungen nach wie vor lediglich den XPath-Standard 1.0 aus dem Jahr 1999.

Wie funktioniert XPath?

XPath liegt ein Datenmodell zugrunde, das XML-Dokumente als eine Sequenz von Elementen interpretiert, die in einer Baumstruktur angeordnet sind. Die Baumstruktur des XPath-Datenmodells ist vergleichbar mit der des Document Object Models (DOM), das als Schnittstelle zwischen HTML und dynamischem JavaScript im Webbrowser fungiert.

Die Lokalisierung von XML-Elementen erfolgt in Anlehnung an das Unix-Verzeichnissystem in Form von Pfaden. Grundbestandteile dieser Lokalisierungspfade sind Knoten, Achsen, Knotentests und Prädikate.

Knotentypen

Die einzelnen Elemente einer XPath-Baumstruktur werden als Knoten bezeichnet. Eine Ordnung der Knoten erfolgt sowohl durch die Dokumentreihenfolge als auch durch Verschachtelung der XML-Elemente.

Das XPath-Datenmodell unterscheidet sieben Knotentypen mit unterschiedlichen Funktionen:

  • Elementknoten (element node)
  • Dokumentknoten (root node) (ab XPath 2.0, vorher Wurzelknoten)
  • Attributknoten (attribute node)
  • Textknoten (text node)
  • Namensraumknoten (namespace node)
  • Verarbeitungsanweisungsknoten (processing instruction node)
  • Kommentarknoten (comment node)

Wir veranschaulichen Ihnen die Knotentypen des XPath-Datenmodells anhand eines Beispiels. Folgendes XML-Dokument dient dem Austausch von Daten im Rahmen einer Buchbestellung und beinhaltet alle sieben Knotentypen.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Order SYSTEM "order.dtd">
<?xml-stylesheet type="text/css" href="style.css"?>
<!--That is a comment!-->
<order date="2019-02-01">
    <address xmlns:shipping="http://localhost/XML/delivery" xmlns:billing="http://localhost/XML/billing">
        <shipping:name>Ellen Adams</shipping:name>
        <shipping:street>123 Maple Street</shipping:street>
        <shipping:city>Mill Valley</shipping:city>
        <shipping:state>CA</shipping:state>
        <shipping:zip>10999</shipping:zip>
        <shipping:country>USA</shipping:country>
        <billing:name>Mary Adams</billing:name>
        <billing:street>8 Oak Avenue</billing:street>
        <billing:city>Old Town</billing:city>
        <billing:state>PA</billing:state>
        <billing:zip>95819</billing:zip>
        <billing:country>USA</billing:country>
    </address>
    <comment>Please use gift wrapping!</comment>
    <items>
        <book isbn="9781408845660">
            <title>Harry Potter and the Prisoner of Azkaban</title>
            <quantity>1</quantity>
            <priceus>22.94</priceus>
            <comment>Please confirm delivery date until Christmas.</comment>
        </book>
        <book isbn="9780544003415">
            <title>The Lord of the Rings</title>
            <quantity>1</quantity>
            <priceus>17.74</priceus>
        </book>
    </items>
</order>

Elementknoten (element node)

In der Baumstruktur des XPath-Datenmodells entspricht jedes Element des XML-Dokuments einem Elementknoten. Ausgenommen davon sind die XML-Deklaration und die Dokumenttyp-Definition am Anfang des Dokuments.

XML-Deklaration:

<!--?xml version="1.0"? encoding="utf-8"?-->

Dokumenttyp-Definition (DTD):

<!DOCTYPE Order SYSTEM "order.dtd">

Elementknoten beginnen mit einem Start-Tag, enden mit einem End-Tag und sind in der Regel ineinander verschachtelt.

Der erste Elementknoten in der Dokumentreihenfolge wird als Wurzelelement bezeichnet.

Das oben dargestellte XML-Dokument beispielsweise enthält als Wurzelelement den Elementknoten order. Dieser fungiert als Elternelement der untergeordneten Elementknoten address, comment und items, die wiederum weitere Elementknoten als Kind-Elemente beinhalten.

Dokumentknoten (document node)

Als Dokumentknoten bezeichnet man die Wurzel der Baumstruktur. Diese ist im XML-Dokument selbst weder visuell manifestiert nicht textuell repräsentiert. Es handelt sich um einen konzeptionellen Knoten, der alle anderen Elemente des Dokuments beinhaltet. Kind-Elemente des Dokumentknotens sind das Wurzelelement sowie ggf. Verarbeitungsanweisungsknoten und Kommentarknoten.

Attributknoten (attribute node)

Die Attribute eines XML-Elements sind im XPath-Datenmodell als Attributknoten repräsentiert. Jeder Attributknoten besteht aus einem Bezeichner und einem dem Attribut zugeordneten Wert.

Im Codebeispiel enthält der erste Elementknoten book den Attributknoten isbn mit dem Wert 9781408845660.

<book isbn="9781408845660"></book>

Attributknoten werden als dem Elementknoten zugehörig betrachtet, nicht jedoch als Kind-Elemente des Elements.

Textknoten (text node)

Zeichendaten innerhalb des Start- und End-Tags eines Elementknotens werden als Textknoten bezeichnet.

Im Codebeispiel enthält der Elementknoten title den Textknoten Harry Potter and the Prisoner of Azkaban.

Harry Potter and the Prisoner of Azkaban

Namensraumknoten

Bei wohlgeformten XML-Dokumenten sind alle verwendeten Element- und Attributnamen einem Namensraum zugeordnet. Die Zuordnung erfolgt in der Regel bereits durch die Dokumenttyp-Definition am Anfang des Dokuments.

Kommen in einem XML-Dokument Elemente oder Attribute unterschiedlicher Namensräume zum Einsatz, wird der jeweilige Namensraum mithilfe des Attributs xmlns oder dem xmlns-Präfix explizit im Start-Tag des betreffenden Elements definiert. Als Wert erwartet das Attribut xmlns einen Uniform Resource Identifier (URI), der angibt, welchem Namensraum das entsprechende Element zuzuordnen ist. Die Zuordnung eines Namensraums zu einem xmlns-Präfix steht dem Element sowie allen Kind-Elementen zur Verfügung. Jeder Namensraum entspricht einem Namensraumknoten in der Baustruktur.

Im Codebeispiel wurden für das XML-Element address zwei Namensräume definiert: xmlns:shipping und xmlns:billing. Die Kind-Elemente des address-Elements tragen die jeweilige Zuordnung als Präfix.

<address xmlns:shipping="http://localhost/XML/delivery" xmlns:billing="http://localhost/XML/ billing">
        <shipping:name>Ellen Adams</shipping:name>
        <shipping:street>123 Maple Street</shipping:street>
        <shipping:city>Mill Valley</shipping:city>
        <shipping:state>CA</shipping:state>
        <shipping:zip>10999</shipping:zip>
        <shipping:country>USA</shipping:country>
        <billing:name>Mary Adams</billing:name>
        <billing:street>8 Oak Avenue</billing:street>
        <billing:city>Old Town</billing:city>
        <billing:state>PA</billing:state>
        <billing:zip>95819</billing:zip>
        <billing:country>USA</billing:country>
    </address>

Das xmlns-Präfix ermöglicht es, gleichnamige Elemente aus unterschiedlichen Namensräumen eindeutig zuzuordnen. Das Element street mit dem Präfix shipping beispielsweise enthält die Straßenangabe der Lieferadresse, das Element street mit dem Präfix billing hingegen die Straßenangabe der Rechnungsadresse.

Verarbeitungsanweisungsknoten (processing instruction node)

Verarbeitungsanweisungen in XML-Dokumenten stehen außerhalb des Dokumentenbaums und werden in der XPath-Terminologie als Verarbeitungsanweisungsknoten bezeichnet. Ein Verarbeitungsknoten beginnt mit <? und endet mit ?>.

Im oben dargestellten Codebeispiel finden Sie die folgende Verarbeitungsanweisung:

<!--?xml-stylesheet type="text/css" href="style.css"?-->

Die XML-Deklaration am Anfang der XML-Datei ist syntaktisch wie eine Verarbeitungsanweisung aufgebaut, gilt jedoch nicht als Verarbeitungsanweisungsknoten im Sinne des XPath-Datenmodells.

Kommentarknoten (comment node)

Als Kommentar ausgezeichnete Inhalte eines XML-Dokuments werden von XPath als Kommentarknoten verarbeitet. Der Knoten umfasst dabei lediglich den ausgezeichneten Zeicheninhalt, nicht das Markup.

Im oben dargestellten Codebeispiel finden Sie folgenden Kommentarknoten:

That is a comment!

Lokalisierungspfade

Die Adressierung von Knoten erfolgt mithilfe sogenannter Lokalisierungspfade. Bei einem Lokalisierungspfad handelt es sich um einen XPath-Ausdruck, der verwendet wird, um durch die Baumstruktur zu navigieren und eine gewünschte Knotenmenge zu selektieren. Die Knotenmenge ist das Ergebnis eines XPath-Ausdrucks.

Lokalisierungspfade werden von links nach rechts ausgewertet. Man unterscheidet zwischen absoluten und relativen Lokalisierungspfaden. Ein absoluter Lokalisierungspfad beginnt am Dokumentknoten. In diesem Fall stellen Sie dem XPath-Ausdruck einen Schrägstrich (/) voran. Relative Lokalisierungspfade beginnen bei einem beliebigen Knoten innerhalb der Baumstruktur. Dieser Ausgangspunkt wird Kontextknoten genannt.

Ein Lokalisierungspfad besteht aus einzelnen Lokalisierungsschritten, die ähnlich wie bei der Adressierung von Dateien in Verzeichnissystemen durch Schrägstriche (/) getrennt sind.

Jeder Lokalisierungsschritt eines Lokalisierungspfads besteht aus bis zu drei Teilen: Achse, Knotentest und eine beliebige Anzahl an Prädikaten.

  • Achse: Mit der Wahl der Achse bestimmen Sie die Richtung der Navigation in der Baumstruktur ausgehend vom Kontext- oder Dokumentknoten.
  • Knotentest: Der Knotentest entspricht einem Filter, mit dem Sie die auf der Achse liegenden Knoten auf die gewünschte Knotenmenge eingrenzen.
  • Prädikate: Prädikate ermöglichen es Ihnen, die durch Achse und Knotentest selektierten Knoten noch einmal zu filtern.

Die Lokalisierungsschritte eines XPath-Ausdrucks werden gemäß folgender Syntax notiert:

achse::knotentest[prädikat1][prädikat2]…
Notation Funktion
/ Fungiert als Pfad-Trennzeichen zwischen zwei Lokalisierungsschritten
:: Fungiert als Pfad-Trennzeichen zwischen Achse und Knotentest

Achsen

Die XPath-Syntax ermöglicht eine Navigation anhand folgender Achsen.

Achse Deutsche Bezeichnung Selektierte Knoten
child Kind Alle direkt untergeordneten Kind-Knoten
parent Elternknoten Der direkt übergeordnete Elternknoten
descendant Nachkommen Alle untergeordnete Knoten
ancestor* Vorfahr Alle übergeordnete Knoten
following Nachfolgende Knoten Alle in der Dokumentreihenfolge nachfolgenden Knoten mit Ausnahme der Nachfahren
preceding* Vorhergehende Knoten Alle in der Dokumentreihenfolge vorangehenden Knoten mit Ausnahme der Vorfahren
following-sibling Nachfolgende Geschwisterknoten Alle nachfolgenden Knoten im XML-Dokument, die vom selben Elternknoten abstammen
preceding-sibling* Vorhergehende Geschwisterknoten Alle vorangehenden Knoten im XML-Dokument, die vom selben Elternknoten abstammen
attribute Attribut Alle Attributknoten eines Elementknotens
namespace Namensraum Alle Namensraumknoten eines Elementknotens; ab Version 2.0 ist diese Achse nicht mehr in der Spezifikation enthalten.
self Aktueller Knoten Der Kontextknoten selbst
descendant-or-self Nachkommen inklusive aktuellem Knoten Alle untergeordneten Knoten inklusive des Kontextknotens
ancestor-or-self* Vorfahren oder aktuelle Knoten Alle übergeordneten Knoten inklusive des Kontextknotens
Hinweis

Bei den mit einem Sternchen (*) gekennzeichneten Achsen handelt es sich um rückwärts gerichtete Anwendungen, die gemäß XPath-Spezifikation Version 1.0 ein optionaler Bestandteil sind und von Anwendungen, die dem Standard entsprechen, nicht zwangsläufig unterstützt werden müssen.

Folgende Grafik zeigt eine schematische Darstellung der wichtigsten Achsen im XPath-Datenmodell ausgehend vom Kontextknoten (rot):

Die Achse child:: beispielsweise wählt alle Kind-Elemente des Kontextknotens D aus: Die Knotenmenge umfasst die Knoten E, H und I.

Knotentest

Mit dem Knotentest definieren Sie einen Filter für die durch die Achse selektierte Knotenmenge. Gemäß der XPath-Spezifikation sind zwei Filterkriterien möglich.

  • Name des Knotens: Geben Sie als Knotentest einen Knotennamen an, um auf der ausgewählten Achse alle Knoten mit dem entsprechenden Namen auszuwählen.
  • Knotentyp: Geben Sie als Knotentest einen Knotentyp an, um auf der ausgewählten Achse alle Knoten mit dem entsprechenden Typ auszuwählen.

Knotenname als Filterkriterium

Mit folgendem Lokalisierungspfad beispielsweise könnten Sie – bezogen auf das oben dargestellte Codebeispiel – vom Dokumentknoten ausgehend alle Nachkommen mit dem Namen book auswählen.

/descendant::book

Möchten Sie hingegen für alle Elementknoten mit dem Namen book das Attribut isbn herausfiltern, benötigen Sie einen Lokalisierungspfad mit zwei Lokalisierungsschritten.

/descendant::book/attribute::isbn

Knotentyp als Filterkriterium

Möchten Sie einen Knotentyp als Filterkriterium für die Selektion der Knotenmenge definieren, nutzen Sie als Knotentest eine der folgenden Funktionen:

Funktion Selektierte Knoten
node() Die Funktion node() wählt alle Knoten auf der ausgewählten Achse aus.
text() Die Funktion text() wählt alle Textknoten auf der ausgewählten Achse aus.
comment() Die Funktion comment() wählt alle Kommentarknoten auf der ausgewählten Achse aus.
processing-instruction() Die Funktion processing-instruction() wählt alle Verarbeitungsanweisungsknoten auf der ausgewählten Achse aus.
Hinweis

Bereits XPath 1.0 definiert 25 Funktionen. Ab XPath 2.0 stehen 111 Funktionen für die Beschreibung von Lokalisierungspfaden zur Verfügung. Eine Übersicht finden Sie in der W3C Recommendation XPath and XQuery Functions and Operators 3.1 von 21. März 2017.

Knotentest mit Wildcard

Verwenden Sie anstelle des Knotentests den Platzhalter * (Sternchen), werden auf der selektierten Achse alle Knoten ausgewählt, die dem Hauptknotentyp der Achse entsprechen. Dabei gilt: Enthält eine Achse Elementknoten, ist dieser Knotentyp der Hauptknotentyp der Achse. Dies trifft auf alle Achsen mit Ausnahme von attribute und namespace zu. Hier gelten Attributknoten bzw. Namensraumknoten als Hauptknotentyp.

Folgender Lokalisierungspfad beispielsweise gibt alle Attribute des aktuellen Kontextknotens aus:

attribute::*

Verkürzte Notation

Für häufig verwendete Achsen und Lokalisierungsschritte wurden Abkürzungen definiert, die statt der englischen Bezeichnungen im XPath-Ausdruck verwendet werden können.

Standardnotation Abkürzung Beispiel
child:: leer Bei child handelt es sich um die Standardachse. Die Achsenbezeichnung kann bei Bedarf weggelassen werden. Der Lokalisierungspfad child::book/child::title entspricht somit der Kurzform book/title.
attribute:: @ Die Achse attribute inklusive Trennzeichen lässt sich mit dem @-Zeichen abkürzen.Der Lokalisierungspfad book/attribute::isbn wählt den Attributknoten isbn des Elements book aus und lautet in der verkürzten Notation book/@isbn.
/descendant-or-self::node()/ // Der Lokalisierungsschritt /descendant-or-self::node()/ wählt den Dokumentknoten und alle Nachfahren aus und wird mit // abgekürzt. Statt /descendant-or-self::node()/child::item schreiben Sie verkürzt //item. Der Lokalisierungspfad wählt alle item-Knoten im Dokument aus.
parent::node() .. Der Lokalisierungsschritt parent::node() wählt den Elternknoten des Kontextknotens aus und wird mit .. abgekürzt.
self::node() . Der Lokalisierungsschritt self::node() wählt den aktuellen Kontextknoten aus und wird mit . abgekürzt.

Prädikate

Mit Prädikaten definieren Sie weitere Filterkriterien für die durch Achse und Knotentest ausgewählte Knotenmenge.

Prädikate bilden den optionalen dritten Teil eines Lokalisierungsschritts und werden in eckigen Klammern notiert. Die Filterkriterien innerhalb der eckigen Klammern werden als Ausdrücke formuliert, die u. a. Pfadausdrücke, Funktionen, Operatoren und Strings enthalten können.

Die XPath-Syntax unterstützt allgemeine Prädikate und numerische Prädikate.

Allgemeine Prädikate

Ausdrücke in allgemeinen Prädikaten filtern die durch die Achse und den Knotentest ausgewählte Knotenmenge, indem sie für jeden Knoten der Auswahl einen booleschen Wert (true oder false) ausgeben. Alle Knoten mit dem Wert true sind Teil der Ergebnismenge.

Die Formulierung von Ausdrücken für allgemeine Prädikate erfolgt anhand von Operatoren. Diese werden verwendet, um gezielt Knoten mit bestimmten Inhalten oder Eigenschaften auszuwählen – beispielsweise alle Knoten, die eine bestimmten Zeichenkette, einen Attributwert oder ein bestimmtes Kind-Element (möglicherweise an einer bestimmten Position) beinhalten.

Die folgenden Tabellen geben Ihnen einen Überblick über die zur Verfügung stehenden Operatoren. Man unterscheidet arithmetische Operatoren, logische Operatoren und Vergleichsoperatoren.

Arithmetische Operatoren Funktion
+ Addition
- Subtraktion
* Multiplikation
div Fließkommateilung
mod Modulo
Vergleichsoperatoren Funktion
= Gleich
!= Ungleich
< Kleiner als; Maskierung innerhalb von XSLT erforderlich (&lt;)
> Größer als; Maskierung innerhalb von XSLT zu empfehlen (&gt;)
<= Kleiner als oder gleich; Maskierung innerhalb von XSLT erforderlich (&lt;)
>= Größer als oder gleich; Maskierung innerhalb von XSLT zu empfehlen (&gt;)
logische Operatoren Funktion
and Logische Und-Verknüpfung
or Logische Oder-Verknüpfung

Im folgenden Beispiel grenzt das Prädikat [title="Harry Potter and the Prisoner of Azkaban"] die Ergebnismenge auf einen Elementknoten namens book ein, dessen Kind-Element title den String Harry Potter and the Prisoner of Azkaban enthält.

Hinweis

Das Beispiel entspricht der XPath-3-Syntax, die u. U. nicht von allen Onlinetools unterstützt wird. Nachvollziehen lassen sich die hier vorgestellten Abfragen beispielsweise mit folgendem Onlinetester: http://videlibri.sourceforge.net/cgi-bin/xidelcgi.

/order/items/book[title="Harry Potter and the Prisoner of Azkaban"]

Wir haben nun den Elementknoten book ausgewählt, der die Daten für das Harry-Potter-Buch beinhaltet.

<book isbn="9781408845660">
        <title>Harry Potter and the Prisoner of Azkaban</title>
        <quantity>1</quantity>
        <priceus>22.94</priceus>
        <comment>Please confirm delivery date until Christmas.</comment>
    </book>

Ein anderes Kind-Element dieses Elementknotens ist das Element comment. Möchten wir dessen Inhalt auswählen, muss der Lokalisierungspfad lediglich um zwei Lokalisierungsschritte erweitert werden.

/order/items/book[title="Harry Potter and the Prisoner of Azkaban"]/comment/text()

Wir navigieren mit dem Lokalisierungsschritt comment (Kurzschreibweise für child::comment) zum gleichnamigen Kind-Element des book-Element und wählen mit der Funktion text() dessen Textknoten aus. Dieser entspricht folgendem String:

Please confirm delivery date until Christmas.

Wird in einem Prädikat lediglich ein Pfadausdruck verwendet, spricht man von einem Existenztest. Mit folgendem Lokalisierungspfad beispielsweise ließe sich testen, ob das oben aufgeführte XML-Dokument einen oder mehrere Knoten namens comment enthält.

Verkürzte Notation:

//book[comment]

Standardnotation:

/descendant-or-self::node()/child::book[child::comment]

Der Lokalisierungspfad //book[comment] wählt alle Knoten mit dem Namen book aus, die ein Kind-Element mit dem Namen comment haben.

Numerische Prädikate

Numerische Prädikate ermöglichen es Ihnen, Knoten anhand Ihrer Position zu adressieren. Folgender Lokalisierungspfad beispielsweise wählt den zweiten Knoten gemäß Dokumentreihenfolge aus, dessen Name book ist:

//book[2]

Genau genommen handelt es sich bei dem Prädikat [2] um die Kurzschreibweise von [position()=2]. XPath selektiert somit zunächst alle Knoten mit dem Namen „book“ und filtert anschließend den Knoten heraus, für den die Funktion position()=2 den booleschen Wert true ergibt.

Hinweis

Anders als anderen Programmiersprachen, beginnt Aufzählungen bei XPath mit 1.

Weiterführende Informationen zur XML Path Language

Einen Überblick über dem aktuellen Entwicklungsstand der XML Path Language sowie alle veröffentlichten Standards und Entwürfe finden Sie auf der Website des W3C.

Kostenlose Informationen und Tools zur Verwendung von XPath im Rahmen von Webanwendungen stehen Ihnen in den MDN-Web-Docs sowie im Microsoft Developer Network zur Verfügung.

Als deutschsprachige Quelle empfehlen wir zudem das Wiki des SELFHTML e. V..

War dieser Artikel hilfreich?
Page top