1. Introduction (Einführung)
1. Introduction (Einführung)
JSON [RFC8259] ist ein verbreitetes Darstellungsformat für strukturierte Datenwerte. JSONPath definiert eine Zeichenketten-Syntax zum Auswählen und Extrahieren von JSON-Werten innerhalb eines gegebenen JSON-Werts.
Im Verhältnis zu JSON Pointer [RFC6901] ist JSONPath nicht als Ersatz, sondern als mächtigerer Begleiter gedacht. Siehe Anhang C.
1.1. Terminology (Terminologie)
Die Schlüsselwörter „MUST“, „MUST NOT“, „REQUIRED“, „SHALL“, „SHALL NOT“, „SHOULD“, „SHOULD NOT“, „RECOMMENDED“, „NOT RECOMMENDED“, „MAY“ und „OPTIONAL“ in diesem Dokument sind wie in BCP 14 [RFC2119] [RFC8174] beschrieben zu interpretieren, und zwar nur dann, wenn sie wie hier in Großbuchstaben erscheinen.
Die grammatikalischen Regeln in diesem Dokument sind als ABNF zu interpretieren, wie in [RFC5234] beschrieben. ABNF-Terminalwerte in diesem Dokument definieren Unicode-Skalare (Unicode Scalar Values) und nicht deren UTF-8-Kodierung. Beispielsweise würde das Unicode-Zeichen PLACE OF INTEREST SIGN (U+2318) in ABNF als %x2318 definiert.
Funktionen werden mit dem Funktionsnamen gefolgt von einem Klammerpaar bezeichnet, wie in fname().
Die Terminologie von [RFC8259] gilt, soweit unten nicht präzisiert. Die Begriffe „primitive“ und „structured“ (primitiv und strukturiert) gruppieren verschiedene Wertarten wie in Abschnitt 1 von [RFC8259]. JSON-Objekte und -Arrays sind strukturiert; alle anderen Werte sind primitiv. Definitionen für „object“, „array“, „number“ und „string“ bleiben unverändert. Wichtig: „object“ und „array“ haben insbesondere keine generische Bedeutung wie in einem allgemeinen Programmierkontext.
Die Terminologie von [RFC9485] gilt.
Zusätzliche in diesem Dokument verwendete Begriffe sind unten definiert.
Value (Wert): Gemäß [RFC8259] ein Datenelement, das dem generischen Datenmodell von JSON entspricht, d. h. primitive Daten (Zahlen, Textzeichenketten und die speziellen Werte null, true und false) oder strukturierte Daten (JSON-Objekte und -Arrays). [RFC8259] konzentriert sich auf die textuelle Darstellung von JSON-Werten und definiert die hier angenommene Wertabstraktion nicht vollständig.
Member (Mitglied): Ein Name/Wert-Paar in einem Objekt. (Ein Mitglied ist selbst kein Wert.)
Name: Der Name (eine Zeichenkette) in einem Name/Wert-Paar, das ein Mitglied bildet. Dies wird auch in [RFC8259] verwendet, aber dort nicht formal definiert. Er wird hier der Vollständigkeit halber aufgeführt.
Element: Ein Wert in einem JSON-Array.
Index: Eine ganze Zahl, die ein bestimmtes Element in einem Array identifiziert.
Query (Abfrage): Kurzname für einen JSONPath-Ausdruck.
Query Argument (Abfrageargument): Kurzname für den Wert, auf den ein JSONPath-Ausdruck angewendet wird.
Location (Position): Die Position eines Werts innerhalb des Abfragearguments. Man kann sie als Sequenz von Namen und Indizes denken, die durch die Objekte und Arrays im Abfrageargument zum Wert navigieren, wobei die leere Sequenz das Abfrageargument selbst bezeichnet. Eine Position kann als Normalized Path (normalisierter Pfad, unten definiert) dargestellt werden.
Node (Knoten): Das Paar aus einem Wert und seiner Position innerhalb des Abfragearguments.
Root Node (Wurzelknoten): Der eindeutige Knoten, dessen Wert das gesamte Abfrageargument ist.
Root Node Identifier (Wurzelknoten-Identifier): Der Ausdruck $, der den Wurzelknoten des Abfragearguments bezeichnet.
Current Node Identifier (Aktueller-Knoten-Identifier): Der Ausdruck @, der den aktuellen Knoten im Kontext der Auswertung eines Filterausdrucks bezeichnet (später beschrieben).
Children (Kinder) (eines Knotens): Wenn der Knoten ein Array ist, die Knoten seiner Elemente; wenn der Knoten ein Objekt ist, die Knoten seiner Mitgliedswerte. Wenn der Knoten weder Array noch Objekt ist, hat er keine Kinder.
Descendants (Nachfahren) (eines Knotens): Die Kinder des Knotens zusammen mit den Kindern seiner Kinder und so rekursiv weiter. Formaler: Die „descendants“-Relation zwischen Knoten ist die transitive Hülle der „children“-Relation.
Depth (Tiefe) (eines Nachfahrenknotens innerhalb eines Werts): Die Anzahl der Vorfahren des Knotens innerhalb des Werts. Der Wurzelknoten des Werts hat Tiefe null, die Kinder des Wurzelknotens haben Tiefe eins, deren Kinder Tiefe zwei usw.
Nodelist (Knotenliste): Eine Liste von Knoten. Obwohl eine Knotenliste in JSON z. B. als Array dargestellt werden kann, verlangt oder setzt dieses Dokument keine bestimmte Darstellung voraus.
Parameter: Formaler Parameter (einer Funktion), der in einem Funktionsausdruck ein Funktionsargument (aktueller Parameter) aufnehmen kann.
Normalized Path (Normalisierter Pfad): Eine Form eines JSONPath-Ausdrucks, der einen Knoten in einem Wert identifiziert, indem er eine Abfrage liefert, die genau diesen Knoten ergib. Jeder Knoten in einem Abfrageargument wird durch genau einen Normalized Path identifiziert (wir sagen, der Normalized Path ist für diesen Knoten „unique“/eindeutig), und um ein Normalized Path für ein bestimmtes Abfrageargument zu sein, muss der Normalized Path genau einen Knoten identifizieren. Das ist ähnlich, aber syntaktisch verschieden von einem JSON Pointer [RFC6901]. Hinweis: Diese Definition basiert auf der syntaktischen Definition in Abschnitt 2.7; JSONPath-Ausdrücke, die einen Knoten in einem Wert identifizieren, aber nicht dieser Syntax entsprechen, sind keine Normalized Paths.
Unicode Scalar Value (Unicode-Skalare): Jeder Unicode-[UNICODE]-Codepunkt außer High- und Low-Surrogate (mit anderen Worten: ganze Zahlen in den inklusiven hexadezimalen Bereichen entweder 0 bis D7FF oder E000 bis 10FFFF). JSONPath-Abfragen sind Sequenzen von Unicode-Skalaren.
Segment: Eines der Konstrukte, das Kinder ([<selectors>]) oder Nachfahren (..[<selectors>]) eines Eingabewerts auswählt.
Selector (Selektor): Ein einzelnes Element innerhalb eines Segments, das den Eingabewert nimmt und eine Knotenliste erzeugt, die aus Kinderknoten des Eingabewerts besteht.
Singular Query (Singuläre Abfrage): Ein JSONPath-Ausdruck aus Segmenten, die syntaktisch in bestimmter Weise eingeschränkt sind (Abschnitt 2.3.5.1), sodass der Ausdruck unabhängig vom Eingabewert eine Knotenliste mit höchstens einem Knoten erzeugt. Hinweis: JSONPath-Ausdrücke, die stets eine singuläre Knotenliste erzeugen, aber nicht der Syntax in Abschnitt 2.3.5.1 entsprechen, sind keine singulären Abfragen.
1.1.1. JSON Values as Trees of Nodes (JSON-Werte als Knotenbäume)
Dieses Dokument modelliert das Abfrageargument als Baum von JSON-Werten, jeweils mit eigenem Knoten. Ein Knoten ist entweder der Wurzelknoten oder einer seiner Nachfahren.
Dieses Dokument modelliert das Ergebnis der Anwendung einer Abfrage auf das Abfrageargument als Knotenliste (eine Liste von Knoten).
Knoten sind die auswählbaren Teile des Abfragearguments. Die einzigen Teile eines Objekts, die durch eine Abfrage ausgewählt werden können, sind die Mitgliedswerte. Mitgliedsnamen und Mitglieder (Name/Wert-Paare) können nicht ausgewählt werden. Daher haben Mitgliedswerte Knoten, Mitglieder und Mitgliedsnamen jedoch nicht. Entsprechend sind Mitgliedswerte Kinder eines Objekts, Mitglieder und Mitgliedsnamen jedoch nicht.
1.2. History (Geschichte)
Dieses Dokument basiert auf Stefan Gössners verbreitetem JSONPath-Vorschlag (datiert 2007-02-21) [JSONPath-orig], stützt sich auf die Erfahrung aus dem flächendeckenden Einsatz seiner Implementierungen und liefert eine normative Spezifikation dafür.
Anhang B beschreibt, wie JSONPath von XMLs XPath [XPath] inspiriert wurde.
JSONPath war als leichtgewichtiger Begleiter zu JSON-Implementierungen in Programmiersprachen wie PHP und JavaScript gedacht; statt eine eigene Ausdruckssprache wie XPath zu definieren, delegierte JSONPath Teile einer Abfrage an die Laufzeitumgebung, z. B. an JavaScripts eval()-Funktion. Mit der Verbreitung auf weitere Umgebungen wurden JSONPath-Ausdrücke zunehmend weniger portabel. Beispielsweise wurde reguläre Ausdrucksverarbeitung oft an eine passende Regex-Engine delegiert.
Dieses Dokument zielt darauf ab, solche implementierungsspezifischen Abhängigkeiten zu entfernen und als gemeinsame JSONPath-Spezifikation zu dienen, die über Programmiersprachen und Umgebungen hinweg nutzbar ist. Das bedeutet, dass Rückwärtskompatibilität nicht immer erreicht wird; ein Entwurfsprinzip dieses Dokuments ist, einen „Konsens“ zwischen Implementierungen zu wählen, auch wenn er grob ist, solange das Ziel einer brauchbaren, stabilen JSON-Abfragesprache nicht gefährdet wird.
Der Begriff JSONPath wurde wegen der XPath-Inspiration und weil das Ergebnis einer Abfrage aus Pfaden besteht, die Knoten im JSON-Abfrageargument identifizieren, gewählt.
1.3. JSON Values (JSON-Werte)
Der JSON-Wert, auf den eine JSONPath-Abfrage angewendet wird, ist definitionsgemäß ein gültiger JSON-Wert. Ein JSON-Wert wird oft durch Parsen eines JSON-Textes erzeugt.
Das Parsen eines JSON-Textes in einen JSON-Wert und das Verhalten, wenn ein JSON-Text kein gültiges JSON darstellt, werden durch dieses Dokument nicht definiert. Die Abschnitte 4 und 8 von [RFC8259] nennen bestimmte Situationen, die der Grammatik für JSON-Texte entsprechen können, aber keine interoperablen JSON-Nutzungen sind, da sie unvorhersagbares Verhalten verursachen können. Dieses Dokument versucht nicht, vorhersagbares Verhalten von JSONPath-Abfragen in diesen Situationen zu definieren.
Insbesondere beschreiben die Unterabschnitte „Semantics“ der Abschnitte 2.3.1, 2.3.2, 2.3.5 und 2.5.2 Verhalten, das unvorhersagbar wird, wenn der JSON-Wert eines der betrachteten Objekte aus JSON-Text erzeugt wurde, der mehrere Mitglieder für ein einzelnes Objekt mit demselben Mitgliedsnamen aufweist („duplicate names“; siehe Abschnitt 4 von [RFC8259]). Außerdem wird beim Auswählen eines Kindes nach Namen (Abschnitt 2.3.1) und beim Vergleichen von Zeichenketten (Abschnitt 2.3.5.2.2) angenommen, dass diese Zeichenketten Sequenzen von Unicode-Skalaren sind; das Verhalten wird unvorhersagbar, wenn dem nicht so ist (Abschnitt 8.2 von [RFC8259]).
1.4. Overview of JSONPath Expressions (Überblick über JSONPath-Ausdrücke)
Ein JSONPath-Ausdruck wird auf einen JSON-Wert angewendet, bekannt als das Abfrageargument. Die Ausgabe ist eine Knotenliste.
Ein JSONPath-Ausdruck besteht aus einem Identifier gefolgt von einer Serie von null oder mehr Segmenten, von denen jedes einen oder mehr Selektoren enthält.
1.4.1. Identifiers (Identifier)
Der Wurzelknoten-Identifier $ bezieht sich auf den Wurzelknoten des Abfragearguments, d. h. auf das Argument als Ganzes.
Der aktuelle-Knoten-Identifier @ bezieht sich auf den aktuellen Knoten im Kontext der Auswertung eines Filterausdrucks (Abschnitt 2.3.5).
1.4.2. Segments (Segmente)
Segmente wählen Kinder ([<selectors>]) oder Nachfahren (..[<selectors>]) eines Eingabewerts aus.
Segmente können Klammernotation (bracket notation) verwenden, zum Beispiel:
$['store']['book'][0]['title']
oder die kompaktere Punktnotation (dot notation), zum Beispiel:
$.store.book[0].title
Die Klammernotation enthält einen oder mehrere (kommagetrennte) Selektoren beliebiger Art. Selektoren werden im nächsten Abschnitt detailliert.
Ein JSONPath-Ausdruck kann eine Kombination aus Klammer- und Punktnotation verwenden.
Dieses Dokument behandelt die Klammernotation als kanonisch und definiert die Kurzform Punktnotation über die Klammernotation. Beispiele und Beschreibungen nutzen die Kurzform, wo es zweckmäßig ist.
1.4.3. Selectors (Selektoren)
Ein Name-Selektor (name selector), z. B. 'name', wählt ein benanntes Kind eines Objekts aus.
Ein Index-Selektor (index selector), z. B. 3, wählt ein indiziertes Kind eines Arrays aus.
Im Ausdruck [] wählt ein Platzhalter * (Abschnitt 2.3.2) alle Kinder eines Knotens aus, und im Ausdruck ..[] alle Nachfahren eines Knotens.
Ein Array-Slice start:end:step (Abschnitt 2.3.4) wählt eine Reihe von Elementen aus einem Array aus mit Startposition, Endposition und optionaler Schrittweite zwischen Start und Ende.
Ein Filterausdruck ?<logical-expr> wählt bestimmte Kinder eines Objekts oder Arrays aus, wie in:
$.store.book[[email protected] < 10].title
1.4.4. Summary (Zusammenfassung)
Tabelle 1 gibt einen kurzen Überblick über die JSONPath-Syntax.
| Syntax Element | Description (Beschreibung) |
|---|---|
| $ | root node identifier (Wurzelknoten-Identifier, Abschnitt 2.2) |
| @ | current node identifier (aktueller-Knoten-Identifier, Abschnitt 2.3.5) |
| (nur innerhalb von Filter-Selektoren gültig) | |
[<selectors>] | child segment (Kind-Segment, Abschnitt 2.5.1): wählt |
| null oder mehr Kinder eines Knotens | |
| .name | Kurzform für ['name'] |
| .* | Kurzform für [*] |
..[<selectors>] | descendant segment (Nachfahren-Segment, Abschnitt 2.5.2): |
| wählt null oder mehr Nachfahren eines Knotens | |
| ..name | Kurzform für ..['name'] |
| ..* | Kurzform für ..[*] |
| 'name' | name selector (Name-Selektor, Abschnitt 2.3.1): wählt ein |
| benanntes Kind eines Objekts | |
| * | wildcard selector (Platzhalter-Selektor, Abschnitt 2.3.2): wählt |
| alle Kinder eines Knotens | |
| 3 | index selector (Index-Selektor, Abschnitt 2.3.3): wählt ein |
| indiziertes Kind eines Arrays (ab 0) | |
| 0💯5 | array slice selector (Array-Slice-Selektor, Abschnitt 2.3.4): |
| start:end:step für Arrays | |
?<logical-expr> | filter selector (Filter-Selektor, Abschnitt 2.3.5): wählt |
| bestimmte Kinder mittels eines logischen | |
| Ausdrucks | |
| length(@.foo) | function extension (Funktionserweiterung, Abschnitt 2.4): ruft |
| eine Funktion in einem Filterausdruck auf |
Tabelle 1: Überblick über die JSONPath-Syntax
1.5. JSONPath Examples (JSONPath-Beispiele)
Dieser Abschnitt ist informativ. Er liefert Beispiele für JSONPath-Ausdrücke.
Die Beispiele basieren auf dem einfachen JSON-Wert in Abbildung 1, der eine Buchhandlung darstellt (die auch ein Fahrrad hat).
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 399
}
}
}
Abbildung 1: Beispiel-JSON-Wert
Tabelle 2 zeigt einige JSONPath-Abfragen, die auf dieses Beispiel angewendet werden könnten, und die beabsichtigten Ergebnisse.
| JSONPath | Intended Result (Beabsichtigtes Ergebnis) |
|---|---|
| $.store.book[*].author | die Autoren aller Bücher im Laden |
| $..author | alle Autoren |
| $.store.* | alle Dinge im Laden, nämlich |
| einige Bücher und ein rotes Fahrrad | |
| $.store..price | die Preise von allem im Laden |
| $..book[2] | das dritte Buch |
| $..book[2].author | der Autor des dritten Buches |
| $..book[2].publisher | leeres Ergebnis: das dritte Buch hat kein |
| Mitglied „publisher“ | |
| $..book[-1] | das letzte Buch in der Reihenfolge |
| $..book[0,1] | die ersten beiden Bücher |
| $..book[:2] | |
| $..book[[email protected]] | alle Bücher mit einer ISBN |
| $..book[[email protected]<10] | alle Bücher günstiger als 10 |
| $..* | alle Mitgliedswerte und Array-Elemente |
| im Eingabewert enthalten |
Tabelle 2: Beispiel-JSONPath-Ausdrücke und beabsichtigte Ergebnisse bei Anwendung auf den Beispiel-JSON-Wert