2.3. Selectors (Selektoren)
2.3. Selectors (Selektoren)
Selektoren erscheinen nur innerhalb von Kind-Segmenten (Abschnitt 2.5.1) und Nachfahren-Segmenten (Abschnitt 2.5.2).
Ein Selektor erzeugt eine Knotenliste aus null oder mehr Kindern des Eingabewerts.
Es gibt verschiedene Selektorarten, die Kinder von Objekten, Kinder von Arrays oder Kinder von Objekten oder Arrays erzeugen.
selector = name-selector /
wildcard-selector /
slice-selector /
index-selector /
filter-selector
Syntax und Semantik jeder Selektorart sind unten definiert.
2.3.1. Name Selector (Name-Selektor)
2.3.1.1. Syntax
Ein Name-Selektor '<name>' wählt höchstens einen Objekt-Mitgliedswert aus.
Im Gegensatz zu JSON erlaubt die JSONPath-Syntax, Zeichenketten in einfachen oder doppelten Anführungszeichen einzuschließen.
name-selector = string-literal
string-literal = %x22 *double-quoted %x22 / ; "string"
%x27 *single-quoted %x27 ; 'string'
double-quoted = unescaped /
%x27 / ; '
ESC %x22 / ; \"
ESC escapable
single-quoted = unescaped /
%x22 / ; "
ESC %x27 / ; \'
ESC escapable
ESC = %x5C ; \ backslash
unescaped = %x20-21 / ; see RFC 8259
; omit 0x22 "
%x23-26 /
; omit 0x27 '
%x28-5B /
; omit 0x5C \
%x5D-D7FF /
; skip surrogate code points
%xE000-10FFFF
escapable = %x62 / ; b BS backspace U+0008
%x66 / ; f FF form feed U+000C
%x6E / ; n LF line feed U+000A
%x72 / ; r CR carriage return U+000D
%x74 / ; t HT horizontal tab U+0009
"/" / ; / slash (solidus) U+002F
"\" / ; \ backslash (reverse solidus) U+005C
(%x75 hexchar) ; uXXXX U+XXXX
hexchar = non-surrogate /
(high-surrogate "\" %x75 low-surrogate)
non-surrogate = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG) /
("D" %x30-37 2HEXDIG )
high-surrogate = "D" ("8"/"9"/"A"/"B") 2HEXDIG
low-surrogate = "D" ("C"/"D"/"E"/"F") 2HEXDIG
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
Anmerkungen:
-
Doppelt quotierte Zeichenketten folgen der JSON-Zeichenketten-Syntax (Abschnitt 7 von [RFC8259]); einfach quotierte folgen einem analogen Muster. Es wurde nicht versucht, diese Syntax zu verbessern; sollen Zeichen mit Skalarwerten über 0xFFFF escaped werden, wie U+1F041 („🁁“, DOMINO TILE HORIZONTAL-02-02), müssen sie durch ein Surrogat-Paar dargestellt werden („\uD83C\uDC41“ in diesem Fall).
-
Alphabetische Zeichen in quotierten Zeichenketten sind in ABNF case-insensitive, daher kann jede hexadezimale Ziffer in \u-Escapes (wie in den von hexchar referenzierten Regeln) klein- oder großgeschrieben sein, während das u in \u kleingeschrieben sein muss (als %x75 angegeben).
2.3.1.2. Semantics (Semantik)
Eine Name-Selektor-Zeichenkette MUSS in einen Mitgliedsnamen M umgewandelt werden, indem die umgebenden Anführungszeichen entfernt und jede Escape-Sequenz durch das äquivalente Unicode-Zeichen ersetzt wird, wie in Tabelle 4 gezeigt:
| Escape Sequence | Unicode Character | Description (Beschreibung) |
|---|---|---|
| \b | U+0008 | BS backspace |
| \t | U+0009 | HT horizontal tab |
| \n | U+000A | LF line feed |
| \f | U+000C | FF form feed |
| \r | U+000D | CR carriage return |
| " | U+0022 | quotation mark |
| ' | U+0027 | apostrophe |
| / | U+002F | slash (solidus) |
| \ | U+005C | backslash (reverse |
| solidus) | ||
| \uXXXX | siehe | hexadecimal escape |
| Abschnitt 2.3.1.1 |
Tabelle 4: Ersetzungen von Escape-Sequenzen
Die Anwendung des Name-Selektors auf einen Objektknoten wählt einen Mitgliedswert, dessen Name dem Mitgliedsnamen M entspricht, oder nichts, wenn es keinen solchen Mitgliedswert gibt. Von einem Wert, der kein Objekt ist, wird nichts ausgewählt.
Hinweis: Die Verarbeitung des Name-Selektors erfordert den Vergleich der Mitgliedsnamen-Zeichenkette M mit Mitgliedsnamen-Zeichenketten im JSON, auf das der Selektor angewendet wird. Zwei Zeichenketten MÜSSEN genau dann als gleich gelten, wenn sie identische Sequenzen von Unicode-Skalaren sind. Mit anderen Worten: Normalisierungsoperationen DÜRFEN weder auf die Mitgliedsnamen-Zeichenkette M aus dem JSONPath noch auf die Mitgliedsnamen-Zeichenketten im JSON vor dem Vergleich angewendet werden.
2.3.1.3. Examples (Beispiele)
JSON:
{
"o": {"j j": {"k.k": 3}},
"'": {"@": 2}
}
Abfragen:
Die Beispiele in Tabelle 5 zeigen den Name-Selektor in Kind-Segmenten.
| Query | Result | Result Paths | Comment |
|---|---|---|---|
| $.o['j j'] | {"k.k": | $['o']['j j'] | Benannter |
| 3} | Wert in | ||
| verschachteltem | |||
| Objekt | |||
| $.o['j j']['k.k'] | 3 | $['o']['j j']['k.k'] | Weitere |
| Verschachtelung | |||
| $.o["j j"]["k.k"] | 3 | $['o']['j j']['k.k'] | Anderer |
| Begrenzer | |||
| in der | |||
| Abfrage, | |||
| unveränderter | |||
| Normalized Path | |||
| $["'"]["@"] | 2 | $[''']['@'] | Ungewöhnliche |
| Mitgliedsnamen |
Tabelle 5: Beispiele Name-Selektor
2.3.2. Wildcard Selector (Platzhalter-Selektor)
2.3.2.1. Syntax
Der Platzhalter-Selektor besteht aus einem Sternchen.
wildcard-selector = "*"
2.3.2.2. Semantics (Semantik)
Ein Platzhalter-Selektor wählt die Knoten aller Kinder eines Objekts oder Arrays aus. Die Reihenfolge, in der die Kinder eines Objekts in der resultierenden Knotenliste erscheinen, ist nicht vorgegeben, da JSON-Objekte ungeordnet sind. Kinder eines Arrays erscheinen in Array-Reihenfolge in der resultierenden Knotenliste.
Beachten Sie, dass die Kinder eines Objekts seine Mitgliedswerte sind, nicht seine Mitgliedsnamen.
Der Platzhalter-Selektor wählt von einem primitiven JSON-Wert (also einer Zahl, Zeichenkette, true, false oder null) nichts aus.
2.3.2.3. Examples (Beispiele)
JSON:
{
"o": {"j": 1, "k": 2},
"a": [5, 3]
}
Abfragen:
Die Beispiele in Tabelle 6 zeigen den Platzhalter-Selektor in einem Kind-Segment.
| Query | Result | Result | Comment |
|---|---|---|---|
| Paths | |||
| $[*] | {"j": 1, | $['o'] | Objektwerte |
| "k": 2} | $['a'] | ||
| [5, 3] | |||
| $.o[*] | 1 | $['o']['j'] | Objektwerte |
| 2 | $['o']['k'] | ||
| $.o[*] | 2 | $['o']['k'] | Alternatives |
| 1 | $['o']['j'] | Ergebnis | |
| $.o[*, | 1 | $['o']['j'] | Nicht-deterministische |
| *] | 2 | $['o']['k'] | Ordnung |
| 2 | $['o']['k'] | ||
| 1 | $['o']['j'] | ||
| $.a[*] | 5 | $['a'][0] | Array-Elemente |
| 3 | $['a'][1] |
Tabelle 6: Beispiele Platzhalter-Selektor
Das Beispiel oben mit der Abfrage $.o[*, *] zeigt, dass der Platzhalter-Selektor bei jedem Auftreten im Kind-Segment Knotenlisten in unterschiedlicher Reihenfolge erzeugen kann, wenn er auf einen Objektknoten mit zwei oder mehr Mitgliedern angewendet wird (nicht jedoch bei Objektknoten mit weniger als zwei Mitgliedern oder bei Array-Knoten).
2.3.3. Index Selector (Index-Selektor)
2.3.3.1. Syntax
Ein Index-Selektor <index> passt auf höchstens einen Array-Elementwert.
index-selector = int ; decimal integer
int = "0" /
(["-"] DIGIT1 *DIGIT) ; - optional
DIGIT1 = %x31-39 ; 1-9 non-zero digit
Die Anwendung des numerischen Index-Selektors wählt das entsprechende Element aus. JSONPath erlaubt negative Indizes (siehe Abschnitt 2.3.3.2).
Damit er gültig ist, MUSS der Index-Selektor-Wert im I-JSON-Bereich exakter Werte liegen (siehe Abschnitt 2.1).
Anmerkungen:
-
Ein Index-Selektor ist eine ganze Zahl (Basis 10, wie bei JSON-Zahlen).
-
Wie bei JSON-Zahlen erlaubt die Syntax keine oktalähnlichen Zahlen mit führenden Nullen, wie 01 oder -01.
2.3.3.2. Semantics (Semantik)
Ein nicht negativer Index-Selektor, angewendet auf ein Array, wählt ein Array-Element mit nullbasiertem Index aus. Beispielsweise wählt der Selektor 0 das erste und der Selektor 4 das fünfte Element eines hinreichend langen Arrays. Wenn der Index außerhalb des Array-Bereichs liegt, wird nichts ausgewählt, und es ist kein Fehler. Von einem Wert, der kein Array ist, wird nichts ausgewählt.
Ein negativer Index-Selektor zählt vom Array-Ende rückwärts und liefert einen äquivalenten nicht negativen Index-Selektor durch Addition der Array-Länge zum negativen Index. Beispielsweise wählt der Selektor -1 das letzte und -2 das vorletzte Element eines Arrays mit mindestens zwei Elementen. Wie bei nicht negativen Indizes ist es kein Fehler, wenn ein solches Element nicht existiert; es wird dann schlicht kein Element ausgewählt.
2.3.3.3. Examples (Beispiele)
JSON:
["a","b"]
Abfragen:
Die Beispiele in Tabelle 7 zeigen den Index-Selektor in einem Kind-Segment.
| Query | Result | Result Paths | Comment |
|---|---|---|---|
| $[1] | "b" | $[1] | Array-Element |
| $[-2] | "a" | $[0] | Array-Element, vom Ende |
Tabelle 7: Beispiele Index-Selektor
2.3.4. Array Slice Selector (Array-Slice-Selektor)
2.3.4.1. Syntax
Der Array-Slice-Selektor hat die Form <start>:<end>:<step>. Er passt auf Elemente von Arrays ab Index <start> bis (aber ohne) <end>, mit Schrittweite step, Standard 1.
slice-selector = [start S] ":" S [end S] [":" [S step ]]
start = int ; included in selection end = int ; not included in selection step = int ; default: 1
Der Slice-Selektor besteht aus drei optionalen Dezimalzahlen, durch Doppelpunkte getrennt. Der zweite Doppelpunkt kann weggelassen werden, wenn die dritte ganze Zahl fehlt.
Damit er gültig ist, MÜSSEN die angegebenen ganzen Zahlen im I-JSON-Bereich exakter Werte liegen (siehe Abschnitt 2.1).
2.3.4.2. Semantics (Semantik)
Der Slice-Selektor wurde inspiriert vom Slice-Operator, der für ECMAScript 4 (ES4) vorgeschlagen, aber nie veröffentlicht wurde, und dem von Python.
2.3.4.2.1. Informal Introduction (Informelle Einführung)
Dieser Abschnitt ist informativ.
Array-Slicing ist inspiriert vom Verhalten der Methode Array.prototype.slice der JavaScript-Sprache, definiert im ECMA-262-Standard [ECMA-262], mit Ergänzung des step-Parameters, inspiriert vom Python-Slice-Ausdruck.
Der Array-Slice-Ausdruck start:end:step wählt Elemente an Indizes ab start, inkrementiert um step, und endet mit end (das selbst ausgeschlossen ist). Beispielsweise wählt der Ausdruck 1:3 (step standardmäßig 1) die Elemente mit den Indizes 1 und 2 (in dieser Reihenfolge), während 1:5:2 die Elemente mit Indizes 1 und 3 wählt.
Wenn step negativ ist, werden Elemente in umgekehrter Reihenfolge ausgewählt. Beispielsweise wählt 5:1:-2 die Elemente mit Indizes 5 und 3 (in dieser Reihenfolge), und ::-1 wählt alle Elemente eines Arrays in umgekehrter Reihenfolge.
Wenn step 0 ist, werden keine Elemente ausgewählt. (Das ist der eine Fall, der sich vom Verhalten von Python unterscheidet, das hier einen Fehler auslöst.)
Der folgende Abschnitt spezifiziert das Verhalten vollständig, ohne von JavaScript oder Python abzuhängen.
2.3.4.2.2. Normative Semantics (Normative Semantik)
Ein Slice-Ausdruck wählt eine Teilmenge der Elemente des Eingabe-Arrays in derselben Reihenfolge wie das Array oder in umgekehrter Reihenfolge, abhängig vom Vorzeichen des step-Parameters. Er wählt von einem Knoten, der kein Array ist, keine Knoten aus.
Ein Slice ist definiert durch die beiden Slice-Parameter start und end sowie die Iterationsschrittweite step. Jeder dieser Parameter ist optional. Im Rest dieses Abschnitts bezeichnet len die Länge des Eingabe-Arrays.
Der Standardwert für step ist 1. Die Standardwerte für start und end hängen vom Vorzeichen von step ab, wie in Tabelle 8 gezeigt.
| Condition | start | end |
|---|---|---|
| step >= 0 | 0 | len |
| step < 0 | len - 1 | -len - 1 |
Tabelle 8: Standardwerte für Array-Slice start und end
Die Slice-Ausdrucksparameter start und end sind nicht direkt als Slice-Grenzen verwendbar und müssen zuerst normalisiert werden. Normalisierung zu diesem Zweck ist definiert als:
FUNCTION Normalize(i, len): IF i >= 0 THEN RETURN i ELSE RETURN len + i END IF
Das Ergebnis des Array-Index-Ausdrucks i, angewendet auf ein Array der Länge len, ist das Ergebnis des Slice-Ausdrucks Normalize(i, len):Normalize(i, len)+1:1.
Die Slice-Parameter start und end werden verwendet, um die Slice-Grenzen lower und upper abzuleiten. Die Iterationsrichtung, definiert durch das Vorzeichen von step, bestimmt, welcher Parameter die untere und welcher die obere Grenze ist:
FUNCTION Bounds(start, end, step, len): n_start = Normalize(start, len) n_end = Normalize(end, len)
IF step >= 0 THEN lower = MIN(MAX(n_start, 0), len) upper = MIN(MAX(n_end, 0), len) ELSE upper = MIN(MAX(n_start, -1), len-1) lower = MIN(MAX(n_end, -1), len-1) END IF
RETURN (lower, upper)
Der Slice-Ausdruck wählt Elemente mit Indizes zwischen lower und upper. Im folgenden Pseudocode ist a(i) das (i+1)-te Element des Arrays a (d. h. a(0) ist das erste Element, a(1) das zweite usw.).
IF step > 0 THEN
i = lower WHILE i < upper: SELECT a(i) i = i + step END WHILE
ELSE if step < 0 THEN
i = upper WHILE lower < i: SELECT a(i) i = i + step END WHILE
END IF
Wenn step = 0 ist, werden keine Elemente ausgewählt, und das Ergebnis-Array ist leer.
2.3.4.3. Examples (Beispiele)
JSON:
["a", "b", "c", "d", "e", "f", "g"]
Abfragen:
Die Beispiele in Tabelle 9 zeigen den Array-Slice-Selektor in einem Kind-Segment.
| Query | Result | Result | Comment |
|---|---|---|---|
| Paths | |||
| $[1:3] | "b" | $[1] | Slice |
| "c" | $[2] | mit | |
| Standard- | |||
| step | |||
| $[5:] | "f" | $[5] | Slice |
| "g" | $[6] | ohne | |
| End- | |||
| Index | |||
| $[1:5:2] | "b" | $[1] | Slice |
| "d" | $[3] | mit | |
| step 2 | |||
| $[5:1:-2] | "f" | $[5] | Slice |
| "d" | $[3] | mit | |
| negativem | |||
| step | |||
| $[::-1] | "g" | $[6] | Slice in |
| "f" | $[5] | umgekehrter | |
| "e" | $[4] | Reihenfolge | |
| "d" | $[3] | ||
| "c" | $[2] | ||
| "b" | $[1] | ||
| "a" | $[0] |
Tabelle 9: Beispiele Array-Slice-Selektor
2.3.5. Filter Selector (Filter-Selektor)
Filter-Selektoren dienen zum Iterieren über die Elemente oder Mitglieder strukturierter Werte, d. h. JSON-Arrays und -Objekte. Die strukturierten Werte werden in der vom Kind- oder Nachfahren-Segment bereitgestellten Knotenliste identifiziert, die den Filter-Selektor verwendet.
Bei jeder Iteration (Element/Mitglied) wird ein logischer Ausdruck (der filter expression / Filterausdruck) ausgewertet, der entscheidet, ob der Knoten des Elements/Mitglieds ausgewählt wird. (Während ein logischer Ausdruck mathematisch einen Booleschen Wert liefert, verwendet diese Spezifikation den Begriff logical / logisch, um eine Unterscheidung zu den Booleschen Werten zu wahren, die JSON darstellen kann.)
Während des Iterationsprozesses erhält der Filterausdruck den Knoten jedes Array-Elements oder Objekt-Mitgliedswerts des gefilterten strukturierten Werts; dieses Element oder dieser Mitgliedswert ist dann der current node / aktuelle Knoten.
Der aktuelle Knoten kann als Start einer oder mehrerer JSONPath-Abfragen in Teilausdrücken des Filterausdrucks verwendet werden, notiert über den Current-Node-Identifier @. Jede JSONPath-Abfrage kann entweder zum Testen der Existenz eines Abfrageergebnisses, zum Gewinnen eines bestimmten JSON-Werts aus dieser Abfrage für einen Vergleich oder als function argument / Funktionsargument dienen.
Filter-Selektoren können Funktionserweiterungen nutzen, behandelt in Abschnitt 2.4. Innerhalb des logischen Ausdrucks für einen Filter-Selektor können Funktionsausdrücke auf Knotenlisten und Werten arbeiten. Die Menge verfügbarer Funktionen ist erweiterbar, mit einer Reihe vordefinierter Funktionen (siehe Abschnitt 2.4) und der Möglichkeit, weitere Funktionen über das Unterregister „Function Extensions“ (Abschnitt 3.2) zu registrieren. Wenn eine Funktion definiert wird, erhält sie einen eindeutigen Namen, und ihr Rückgabewert sowie jeder Parameter erhält einen declared type / deklarierten Typ. Das Typsystem ist begrenzt; sein Zweck ist, Einschränkungen auszudrücken, die ohne Funktionen implizit in der Grammatik von Filterausdrücken stecken. Das Typsystem leitet auch Konvertierungen (Abschnitt 2.4.2) an, die nachahmen, wie verschiedene Ausdrucksarten in der Grammatik behandelt werden, wenn keine Funktionsausdrücke verwendet werden.
2.3.5.1. Syntax
Der Filter-Selektor hat die Form ?<logical-expr>.
filter-selector = "?" S logical-expr
Da der Filterausdruck aus nebenwirkungsfreien Bestandteilen besteht, muss die Auswertungsreihenfolge nicht (und ist nicht) definiert. Entsprechend führen bei Konjunktion (&&) und Disjunktion (||) (später definiert) sowohl Kurzschluss- als auch vollständig auswertende Implementierungen zum selben Ergebnis; beide Strategien sind gültig.
Der aktuelle Knoten ist über den Current-Node-Identifier @ erreichbar. Dieser Identifier adressiert den aktuellen Knoten des Filter-Selektors, der den Identifier unmittelbar umschließt. Hinweis: Innerhalb verschachtelter Filter-Selektoren gibt es keine Syntax, um den aktuellen Knoten eines anderen als des unmittelbar umschließenden Filter-Selektors anzusprechen (d. h. von Filter-Selektoren, die den Filter-Selektor umschließen, der den Identifier unmittelbar umschließt).
Logische Ausdrücke bieten die üblichen Booleschen Operatoren (|| für OR, && für AND und ! für NOT). Sie haben die normale Semantik der Booleschen Algebra und gehorchen deren Gesetzen (siehe z. B. [BOOLEAN-LAWS]). Klammern KÖNNEN innerhalb von logical-expr zur Gruppierung verwendet werden.
Es ist nicht erforderlich, dass logical-expr aus einem geklammerten Ausdruck besteht (was in [JSONPath-orig] erforderlich war), obwohl er es kann, und die Semantik ist dieselbe wie ohne Klammern.
logical-expr = logical-or-expr logical-or-expr = logical-and-expr *(S "||" S logical-and-expr) ; disjunction ; binds less tightly than conjunction logical-and-expr = basic-expr *(S "&&" S basic-expr) ; conjunction ; binds more tightly than disjunction
basic-expr = paren-expr /
comparison-expr /
test-expr
paren-expr = [logical-not-op S] "(" S logical-expr S ")" ; parenthesized expression logical-not-op = "!" ; logical NOT operator
Ein Testausdruck testet entweder die Existenz eines durch eine eingebettete Abfrage bezeichneten Knotens (siehe Abschnitt 2.3.5.2.1) oder das Ergebnis eines Funktionsausdrucks (siehe Abschnitt 2.4). Im letzteren Fall testet er, wenn der deklarierte Ergebnistyp der Funktion LogicalType ist (siehe Abschnitt 2.4.1), ob das Ergebnis LogicalTrue ist; wenn der deklarierte Ergebnistyp NodesType ist, ob das Ergebnis nicht leer ist. Wenn der deklarierte Ergebnistyp ValueType ist, ist die Verwendung in einem Testausdruck nicht wohlgetypt (siehe Abschnitt 2.4.3).
test-expr = [logical-not-op S]
(filter-query / ; existence/non-existence
function-expr) ; LogicalType or NodesType
filter-query = rel-query / jsonpath-query
rel-query = current-node-identifier segments
current-node-identifier = "@"
Vergleichsausdrücke sind für Vergleiche zwischen primitiven Werten (Zahlen, Zeichenketten, true, false und null) verfügbar. Diese können über Literalwerte; singuläre Abfragen, von denen jede höchstens einen Knoten auswählt, dessen Wert dann verwendet wird; oder Funktionsausdrücke (siehe Abschnitt 2.4) vom Typ ValueType bezogen werden.
comparison-expr = comparable S comparison-op S comparable
literal = number / string-literal /
true / false / null
comparable = literal /
singular-query / ; singular query value
function-expr ; ValueType
comparison-op = "==" / "!=" /
"<=" / ">=" /
"<" / ">"
singular-query = rel-singular-query / abs-singular-query
rel-singular-query = current-node-identifier singular-query-segments
abs-singular-query = root-identifier singular-query-segments
singular-query-segments = *(S (name-segment / index-segment))
name-segment = ("[" name-selector "]") /
("." member-name-shorthand)
index-segment = "[" index-selector "]"
Literale können wie üblich für JSON notiert werden (mit der Erweiterung, dass Zeichenketten einfache Anführungszeichen als Begrenzer nutzen dürfen).
Hinweis: Alphabetische Zeichen in quotierten Zeichenketten sind in ABNF case-insensitive, daher kann der ABNF-Ausdruck „e“ in einer Gleitkommazahl entweder das Zeichen 'e' oder 'E' sein.
true, false und null sind nur kleingeschrieben (groß/klein-sensitiv).
number = (int / "-0") [ frac ] [ exp ] ; decimal number
frac = "." 1*DIGIT ; decimal fraction
exp = "e" [ "-" / "+" ] 1*DIGIT ; decimal exponent
true = %x74.72.75.65 ; true
false = %x66.61.6c.73.65 ; false
null = %x6e.75.6c.6c ; null
Tabelle 10 listet Filterausdrucks-Operatoren in Reihenfolge der Bindungsstärke von höchster (bindet am stärksten) zu niedrigster.
| Precedence | Operator type | Syntax | ||
|---|---|---|---|---|
| 5 | Grouping | (...) | ||
| Function Expressions | name(...) | |||
| 4 | Logical NOT | ! | ||
| 3 | Relations | == != | ||
| <= > >= | ||||
| 2 | Logical AND | && | ||
| 1 | Logical OR |
Tabelle 10: Operator-Vorrang in Filterausdrücken
2.3.5.2. Semantics (Semantik)
Der Filter-Selektor arbeitet ausschließlich mit Arrays und Objekten. Sein Ergebnis ist eine Liste von (null, einem, mehreren oder allen) ihren Array-Elementen bzw. Mitgliedswerten. Angewendet auf einen primitiven Wert wählt er nichts aus (und trägt daher nicht zum Ergebnis des Filter-Selektors bei).
In der resultierenden Knotenliste sind Kinder eines Arrays nach ihrer Position im Array geordnet. Die Reihenfolge der Kinder eines Objekts (im Gegensatz zu einem Array) in der resultierenden Knotenliste ist nicht vorgegeben, da JSON-Objekte ungeordnet sind.
2.3.5.2.1. Existence Tests (Existenztests)
Eine Abfrage allein in einem logischen Kontext ist ein Existenztest: sie liefert true, wenn die Abfrage mindestens einen Knoten auswählt, und false, wenn sie keinen Knoten auswählt.
Existenztests unterscheiden sich von Vergleichen dadurch, dass:
-
sie mit beliebigen relativen oder absoluten Abfragen arbeiten (nicht nur singulären Abfragen).
-
sie mit Abfragen arbeiten, die strukturierte Werte auswählen.
Um den Wert eines durch eine Abfrage ausgewählten Knotens zu prüfen, ist ein expliziter Vergleich nötig. Beispielsweise prüft @.foo == null (siehe Abschnitt 2.6), ob der durch @.foo ausgewählte Knoten den Wert null hat, nicht der negierte Existenztest [email protected] (der false liefert, wenn @.foo einen Knoten auswählt, unabhängig vom Knotenwert). Entsprechend liefert @.foo == false nur dann true, wenn @.foo einen Knoten auswählt und der Wert dieses Knotens false ist.
2.3.5.2.2. Comparisons (Vergleiche)
Die Vergleichsoperatoren == und < werden zuerst definiert; daraus werden !=, <=, > und >= abgeleitet.
Wenn eine Seite eines Vergleichs eine leere Knotenliste oder das spezielle Ergebnis Nothing ergibt (siehe Abschnitt 2.4.1):
-
ein Vergleich mit == liefert true genau dann, wenn die andere Seite ebenfalls eine leere Knotenliste oder Nothing ergibt.
-
ein Vergleich mit < liefert false.
Wenn eine Abfrage oder ein Funktionsausdruck auf einer Seite eines Vergleichs eine Knotenliste mit genau einem Knoten ergibt, wird diese Seite durch den Wert ihres Knotens ersetzt und dann:
-
== liefert true genau dann, wenn der Vergleich zwischen folgenden Fällen liegt:
-
Zahlen, die gemäß Abschnitt 2.2 von I-JSON [RFC7493] interoperieren sollen und mit normaler mathematischer Gleichheit gleich sind,
-
Zahlen, von denen mindestens eine nicht gemäß I-JSON interoperieren soll, wo die Zahlen mit implementierungsspezifischer Gleichheit gleich sind,
-
gleichen primitiven Werten, die keine Zahlen sind,
-
gleichen Arrays, d. h. Arrays gleicher Länge, bei denen jedes Element des ersten Arrays dem entsprechenden Element des zweiten gleich ist, oder
-
gleichen Objekten ohne doppelte Namen, d. h. wo:
o beide Objekte dieselbe Menge von Namen haben (ohne Duplikate) und
o für jeden dieser Namen die den Namen zugeordneten Werte in beiden Objekten gleich sind.
-
< liefert true genau dann, wenn der Vergleich zwischen Werten liegt, die beide Zahlen oder beide Zeichenketten sind und die den Vergleich erfüllen:
-
Zahlen, die gemäß I-JSON [RFC7493] interoperieren sollen, MÜSSEN mit normaler mathematischer Ordnung verglichen werden; Zahlen, die nicht gemäß I-JSON interoperieren sollen, KÖNNEN mit implementierungsspezifischer Ordnung verglichen werden,
-
die leere Zeichenkette ist kleiner als jede nicht leere Zeichenkette, und
-
eine nicht leere Zeichenkette ist kleiner als eine andere nicht leere genau dann, wenn die erste mit einem kleineren Unicode-Skalaren beginnt als die zweite oder beide mit demselben Unicode-Skalaren beginnen und der Rest der ersten kleiner ist als der Rest der zweiten.
!=, <=, > und >= sind über die anderen Vergleichsoperatoren definiert. Für beliebige a und b:
-
a != b liefert true genau dann, wenn a == b false liefert.
-
a <= b liefert true genau dann, wenn a < b true liefert oder a == b true liefert.
-
a > b liefert true genau dann, wenn b < a true liefert.
-
a >= b liefert true genau dann, wenn b < a false liefert oder a == b true liefert.
2.3.5.3. Examples (Beispiele)
Die erste Beispielgruppe zeigt einige Vergleichsausdrücke und ihr Ergebnis bei gegebenem JSON-Eingabewert.
JSON:
{
"obj": {"x": "y"},
"arr": [2, 3]
}
Vergleiche:
| Comparison | Result | Comment |
|---|---|---|
| $.absent1 == $.absent2 | true | Leere Knotenlisten |
| $.absent1 <= $.absent2 | true | == impliziert <= |
| $.absent == 'g' | false | Leere Knotenliste |
| $.absent1 != $.absent2 | false | Leere Knotenlisten |
| $.absent != 'g' | true | Leere Knotenliste |
| 1 <= 2 | true | Zahlenvergleich |
| 1 > 2 | false | Zahlenvergleich |
| 13 == '13' | false | Typkonflikt |
| 'a' <= 'b' | true | Zeichenkettenvergleich |
| 'a' > 'b' | false | Zeichenkettenvergleich |
| $.obj == $.arr | false | Typkonflikt |
| $.obj != $.arr | true | Typkonflikt |
| $.obj == $.obj | true | Objektvergleich |
| $.obj != $.obj | false | Objektvergleich |
| $.arr == $.arr | true | Arrayvergleich |
| $.arr != $.arr | false | Arrayvergleich |
| $.obj == 17 | false | Typkonflikt |
| $.obj != 17 | true | Typkonflikt |
| $.obj <= $.arr | false | Objekte und Arrays |
| erlauben keinen <-Vergleich | ||
| $.obj < $.arr | false | Objekte und Arrays |
| erlauben keinen <-Vergleich | ||
| $.obj <= $.obj | true | == impliziert <= |
| $.arr <= $.arr | true | == impliziert <= |
| 1 <= $.arr | false | Arrays erlauben keinen < |
| Vergleich | ||
| 1 >= $.arr | false | Arrays erlauben keinen < |
| Vergleich | ||
| 1 > $.arr | false | Arrays erlauben keinen < |
| Vergleich | ||
| 1 < $.arr | false | Arrays erlauben keinen < |
| Vergleich | ||
| true <= true | true | == impliziert <= |
| true > true | false | Booleans erlauben keinen |
| <-Vergleich |
Tabelle 11: Beispiele Vergleiche
Die zweite Beispielgruppe zeigt vollständige JSONPath-Abfragen mit Filter-Selektoren und die Ergebnisse bei gegebenem JSON-Eingabewert. (Hinweis: Zwei der Abfragen nutzen Funktionserweiterungen; siehe die Abschnitte 2.4.6 und 2.4.7.)
JSON:
{
"a": [3, 5, 1, 2, 4, 6,
{"b": "j"},
{"b": "k"},
{"b": {}},
{"b": "kilo"}
],
"o": {"p": 1, "q": 2, "r": 3, "s": 5, "t": {"u": 6}},
"e": "f"
}
Abfragen:
Die Beispiele in Tabelle 12 zeigen den Filter-Selektor in einem Kind-Segment.
| Query | Result | Result | Comment | ||
|---|---|---|---|---|---|
| Paths | |||||
| $.a[[email protected] == | {"b": | $['a'][9] | Mitgliedswert- | ||
| 'kilo'] | "kilo"} | vergleich | |||
| $.a[?(@.b == | {"b": | $['a'][9] | Äquivalente Abfrage | ||
| 'kilo')] | "kilo"} | mit umschließenden | |||
| Klammern | |||||
| $.a[?@>3.5] | 5 | $['a'][1] | Array-Wert- | ||
| 4 | $['a'][4] | vergleich | |||
| 6 | $['a'][5] | ||||
| $.a[[email protected]] | {"b": "j"} | $['a'][6] | Array-Wert- | ||
| {"b": "k"} | $['a'][7] | Existenz | |||
| {"b": {}} | $['a'][8] | ||||
| {"b": | $['a'][9] | ||||
| "kilo"} | |||||
| $[?@.*] | [3, 5, 1, | $['a'] | Existenz nicht- | ||
| 2, 4, 6, | $['o'] | singulärer Abfragen | |||
| {"b": "j"}, | |||||
| {"b": "k"}, | |||||
| {"b": {}}, | |||||
| {"b": | |||||
| "kilo"}] | |||||
| {"p": 1, | |||||
| "q": 2, | |||||
| "r": 3, | |||||
| "s": 5, | |||||
| "t": {"u": | |||||
| 6}} | |||||
| $[?@[[email protected]]] | [3, 5, 1, | $['a'] | Verschachtelte Filter | ||
| 2, 4, 6, | |||||
| {"b": "j"}, | |||||
| {"b": "k"}, | |||||
| {"b": {}}, | |||||
| {"b": | |||||
| "kilo"}] | |||||
| $.o[?@<3, ?@<3] | 1 | $['o']['p'] | Nicht-deterministische | ||
| 2 | $['o']['q'] | Ordnung | |||
| 2 | $['o']['q'] | ||||
| 1 | $['o']['p'] | ||||
| $.a[?@<2 | @.b | 1 | $['a'][2] | Array-Wert- | |
| == "k"] | {"b": "k"} | $['a'][7] | logisches OR | ||
| $.a[?match(@.b, | {"b": "j"} | $['a'][6] | Array-Wert- | ||
| "[jk]")] | {"b": "k"} | $['a'][7] | Regex-Match | ||
| $.a[?search(@.b, | {"b": "j"} | $['a'][6] | Array-Wert- | ||
| "[jk]")] | {"b": "k"} | $['a'][7] | Regex-Suche | ||
| {"b": | $['a'][9] | ||||
| "kilo"} | |||||
| $.o[?@>1 && @<4] | 2 | $['o']['q'] | Objektwert- | ||
| 3 | $['o']['r'] | logisches AND | |||
| $.o[?@>1 && @<4] | 3 | $['o']['r'] | Alternatives | ||
| 2 | $['o']['q'] | Ergebnis | |||
| $.o[[email protected] | @.x] | {"u": 6} | $['o']['t'] | Objektwert- | |
| logisches OR | |||||
| $.a[[email protected] == $.x] | 3 | $['a'][0] | Vergleich von | ||
| 5 | $['a'][1] | Abfragen ohne | |||
| 1 | $['a'][2] | Werte | |||
| 2 | $['a'][3] | ||||
| 4 | $['a'][4] | ||||
| 6 | $['a'][5] | ||||
| $.a[?@ == @] | 3 | $['a'][0] | Vergleiche primitiver | ||
| 5 | $['a'][1] | und strukturierter | |||
| 1 | $['a'][2] | Werte | |||
| 2 | $['a'][3] | ||||
| 4 | $['a'][4] | ||||
| 6 | $['a'][5] | ||||
| {"b": "j"} | $['a'][6] | ||||
| {"b": "k"} | $['a'][7] | ||||
| {"b": {}} | $['a'][8] | ||||
| {"b": | $['a'][9] | ||||
| "kilo"} |
Tabelle 12: Beispiele Filter-Selektor
Das Beispiel oben mit der Abfrage $.o[?@<3, ?@<3] zeigt, dass ein Filter-Selektor bei jedem Auftreten im Kind-Segment Knotenlisten in unterschiedlicher Reihenfolge erzeugen kann.