2.4. Function Extensions (Funktionserweiterungen)
2.4. Function Extensions (Funktionserweiterungen)
Über die in den vorangehenden Unterabschnitten definierte Filterausdrucks-Funktionalität hinaus definiert JSONPath einen Erweiterungspunkt zum Hinzufügen von Filterausdrucks-Funktionalität: „Function Extensions“ (Funktionserweiterungen).
Dieser Abschnitt definiert den Erweiterungspunkt und einige Funktionserweiterungen, die diesen nutzen. Obwohl diese Mechanismen den Erweiterungspunkt nutzen sollen, sind sie integraler Bestandteil der JSONPath-Spezifikation und werden wie jeder andere integrale Teil erwartungsgemäß implementiert.
Eine Funktionserweiterung definiert einen registrierten Namen (siehe Abschnitt 3.2), der auf eine Sequenz von null oder mehr Argumenten angewendet werden kann und ein Ergebnis erzeugt. Jeder registrierte Funktionsname ist eindeutig.
Eine Funktionserweiterung MUSS so definiert sein, dass ihre Auswertung frei von Seitenwirkungen ist, d. h. alle möglichen Auswertungsreihenfolgen und Wahlen zwischen Kurzschluss- und Vollauswertung eines sie enthaltenden Ausdrucks MÜSSEN zum selben Ergebnis führen. (Hinweis: Memoization oder Protokollierung sind in diesem Sinne keine Seitenwirkungen, da sie nur auf Implementierungsebene sichtbar sind – sie beeinflussen das Auswertungsergebnis nicht.)
function-name = function-name-first *function-name-char
function-name-first = LCALPHA
function-name-char = function-name-first / "_" / DIGIT
LCALPHA = %x61-7A ; "a".."z"
function-expr = function-name "(" S [function-argument
*(S "," S function-argument)] S ")"
function-argument = literal /
filter-query / ; (includes singular-query)
logical-expr /
function-expr
Funktionsausdrücke in einer Abfrage müssen wohlgeformt (konform zur obigen ABNF) und wohlgetypt sein; andernfalls MUSS die JSONPath-Implementierung einen Fehler melden (siehe Abschnitt 2.1). Um festzulegen, welche Funktionsausdrücke wohlgetypt sind, wird zuerst ein Typsystem eingeführt.
2.4.1. Type System for Function Expressions (Typsystem für Funktionsausdrücke)
Jeder Parameter und das Ergebnis einer Funktionserweiterung müssen einen deklarierten Typ haben.
Deklarierte Typen ermöglichen die Prüfung einer JSONPath-Abfrage auf Wohlgetyptheit unabhängig von jedem Abfrageargument, auf das die Abfrage angewendet wird.
Tabelle 13 definiert die verfügbaren Typen anhand der Instanzen, die sie enthalten.
| Type | Instances (Instanzen) |
|---|---|
| ValueType | JSON-Werte oder Nothing |
| LogicalType | LogicalTrue oder LogicalFalse |
| NodesType | Knotenlisten |
Tabelle 13: Typsystem für Funktionserweiterungen
Anmerkungen:
-
Die einzigen Instanzen, die direkt in der JSONPath-Syntax dargestellt werden können, sind bestimmte JSON-Werte in ValueType als Literale (die in JSONPath auf primitive Werte beschränkt sind).
-
Das spezielle Ergebnis Nothing steht für das Fehlen eines JSON-Werts und ist von jedem JSON-Wert einschließlich null verschieden.
-
LogicalTrue und LogicalFalse stehen in keinem Zusammenhang zu den JSON-Werten der Literale true und false.
2.4.2. Type Conversion (Typkonvertierung)
So wie Abfragen in logischen Ausdrücken durch Testen auf Existenz mindestens eines Knotens verwendet werden können (Abschnitt 2.3.5.2.1), kann ein Funktionsausdruck mit deklariertem Typ NodesType als Funktionsargument für einen Parameter mit deklariertem Typ LogicalType verwendet werden, mit der äquivalenten Konvertierungsregel:
-
Enthält die Knotenliste einen oder mehr Knoten, ist das Konvertierungsergebnis LogicalTrue.
-
Ist die Knotenliste leer, ist das Konvertierungsergebnis LogicalFalse.
Anmerkungen:
-
Die Extraktion eines Werts aus einer Knotenliste kann auf mehrere Arten erfolgen; eine implizite Konvertierung von NodesType zu ValueType könnte überraschen und wurde daher nicht definiert.
-
Ein Funktionsausdruck mit deklariertem Typ NodesType kann indirekt als Argument für einen Parameter mit deklariertem Typ ValueType verwendet werden, indem der Ausdruck in einen Aufruf einer Funktionserweiterung wie value() (siehe Abschnitt 2.4.8) eingebettet wird, die einen Parameter vom Typ NodesType und ein Ergebnis vom Typ ValueType hat.
Die Wohlgetyptheit von Funktionsausdrücken kann nun anhand dieses Typsystems definiert werden.
2.4.3. Well-Typedness of Function Expressions (Wohlgetyptheit von Funktionsausdrücken)
Damit ein Funktionsausdruck wohlgetypt ist:
- Sein deklarierter Typ muss im Kontext, in dem er vorkommt, wohlgetypt sein.
Gemäß Grammatik kann ein Funktionsausdruck in drei unmittelbaren Kontexten vorkommen, was zu folgenden Bedingungen für Wohlgetyptheit führt:
Als test-expr in einem logischen Ausdruck: Der deklarierte Ergebnistyp der Funktion ist LogicalType oder (mit Konvertierung gemäß Abschnitt 2.4.2) NodesType.
Als comparable in einem Vergleich: Der deklarierte Ergebnistyp der Funktion ist ValueType.
Als function-argument in einem anderen Funktionsausdruck: Der deklarierte Ergebnistyp der Funktion erfüllt die Regeln für den entsprechenden Parameter der umschließenden Funktion.
- Seine Argumente müssen für die deklarierten Typen der entsprechenden Parameter wohlgetypt sein.
Die Argumente des Funktionsausdrucks sind wohlgetypt, wenn jedes Argument für den deklarierten Typ des entsprechenden Parameters gemäß einer der folgenden Bedingungen verwendet werden kann:
-
Wenn das Argument ein Funktionsausdruck mit demselben deklarierten Ergebnistyp wie der deklarierte Typ des Parameters ist.
-
Wenn der deklarierte Typ des Parameters LogicalType ist und das Argument eines der folgenden ist:
-
Ein Funktionsausdruck mit deklariertem Ergebnistyp NodesType. In diesem Fall wird das Argument gemäß Abschnitt 2.4.2 zu LogicalType konvertiert.
-
Ein logical-expr, der kein Funktionsausdruck ist.
-
Wenn der deklarierte Typ des Parameters NodesType ist und das Argument eine Abfrage ist (einschließlich singulärer Abfrage).
-
Wenn der deklarierte Typ des Parameters ValueType ist und das Argument eines der folgenden ist:
-
Ein als Literal ausgedrückter Wert.
-
Eine singuläre Abfrage. In diesem Fall:
o Ergibt die Abfrage eine Knotenliste mit genau einem Knoten, ist das Argument der Wert des Knotens.
o Ergibt die Abfrage eine leere Knotenliste, ist das Argument das spezielle Ergebnis Nothing.
2.4.4. length() Function Extension (Funktionserweiterung length())
Parameter: 1. ValueType
Ergebnis: ValueType (vorzeichenlose ganze Zahl oder Nothing)
Die Funktionserweiterung length() ermöglicht die Berechnung der Länge eines Werts und deren Nutzung in der weiteren Verarbeitung im Filterausdruck:
$[?length(@.authors) >= 5]
Ihr einziges Argument ist eine Instanz von ValueType (möglicherweise aus einer singulären Abfrage wie im Beispiel). Das Ergebnis ist ebenfalls eine Instanz von ValueType: eine vorzeichenlose ganze Zahl oder das spezielle Ergebnis Nothing.
-
Ist der Argumentwert eine Zeichenkette, ist das Ergebnis die Anzahl der Unicode-Skalare in der Zeichenkette.
-
Ist der Argumentwert ein Array, ist das Ergebnis die Anzahl der Elemente im Array.
-
Ist der Argumentwert ein Objekt, ist das Ergebnis die Anzahl der Mitglieder im Objekt.
-
Für jeden anderen Argumentwert ist das Ergebnis Nothing.
2.4.5. count() Function Extension (Funktionserweiterung count())
Parameter: 1. NodesType
Ergebnis: ValueType (vorzeichenlose ganze Zahl)
Die Funktionserweiterung count() ermöglicht die Ermittlung der Anzahl von Knoten in einer Knotenliste und deren Nutzung in der weiteren Verarbeitung im Filterausdruck:
$[?count(@.*.author) >= 5]
Ihr einziges Argument ist eine Knotenliste. Das Ergebnis ist ein Wert (vorzeichenlose ganze Zahl), der die Anzahl der Knoten in der Knotenliste angibt.
Anmerkungen:
-
Es gibt keine Deduplizierung der Knotenliste.
-
Die Anzahl der Knoten in der Knotenliste wird unabhängig von ihren Werten oder etwaigen Kindern gezählt, z. B. ist count(@) für eine nicht leere singuläre Knotenliste stets 1.
2.4.6. match() Function Extension (Funktionserweiterung match())
Parameter: 1. ValueType (Zeichenkette)
- ValueType (Zeichenkette gemäß [RFC9485])
Ergebnis: LogicalType
Die Funktionserweiterung match() ermöglicht zu prüfen, ob (die gesamte; siehe Abschnitt 2.4.7) eine gegebene Zeichenkette mit einem gegebenen regulären Ausdruck übereinstimmt, in der in [RFC9485] beschriebenen Form.
$[?match(@.date, "1974-05-..")]
Ihre Argumente sind Instanzen von ValueType (möglicherweise aus singulären Abfragen wie das erste Argument im Beispiel). Ist das erste Argument keine Zeichenkette oder das zweite keine gemäß [RFC9485] konforme Zeichenkette, ist das Ergebnis LogicalFalse. Andernfalls wird die erste Argumentzeichenkette gegen die in der zweiten Zeichenkette enthaltene I-Regexp gematcht; das Ergebnis ist LogicalTrue, wenn die Zeichenkette passt, andernfalls LogicalFalse.
2.4.7. search() Function Extension (Funktionserweiterung search())
Parameter: 1. ValueType (Zeichenkette)
- ValueType (Zeichenkette gemäß [RFC9485])
Ergebnis: LogicalType
Die Funktionserweiterung search() ermöglicht zu prüfen, ob eine gegebene Zeichenkette eine Teilzeichenkette enthält, die mit einem gegebenen regulären Ausdruck übereinstimmt, in der in [RFC9485] beschriebenen Form.
$[?search(@.author, "[BR]ob")]
Ihre Argumente sind Instanzen von ValueType (möglicherweise aus singulären Abfragen wie das erste Argument im Beispiel). Ist das erste Argument keine Zeichenkette oder das zweite keine gemäß [RFC9485] konforme Zeichenkette, ist das Ergebnis LogicalFalse. Andernfalls wird in der ersten Argumentzeichenkette nach einer Teilzeichenkette gesucht, die der in der zweiten Zeichenkette enthaltenen I-Regexp entspricht; das Ergebnis ist LogicalTrue, wenn mindestens eine solche Teilzeichenkette existiert, andernfalls LogicalFalse.
2.4.8. value() Function Extension (Funktionserweiterung value())
Parameter: 1. NodesType
Ergebnis: ValueType
Die Funktionserweiterung value() wandelt eine Instanz von NodesType in einen Wert um und macht ihn für die weitere Verarbeitung im Filterausdruck verfügbar:
$[?value(@..color) == "red"]
Ihr einziges Argument ist eine Instanz von NodesType (möglicherweise aus einer filter-query wie im Beispiel). Das Ergebnis ist eine Instanz von ValueType.
-
Enthält das Argument genau einen Knoten, ist das Ergebnis der Wert des Knotens.
-
Ist das Argument die leere Knotenliste oder enthält es mehrere Knoten, ist das Ergebnis Nothing.
Hinweis: Eine singuläre Abfrage kann überall dort verwendet werden, wo ValueType erwartet wird; daher ist value() für eine singuläre Abfrage nicht nötig.
2.4.9. Examples (Beispiele)
| Query | Comment (Kommentar) |
|---|---|
| $[?length(@) < 3] | wohlgetypt |
| $[?length(@.*) < 3] | nicht wohlgetypt, da @.* eine nicht- |
| singuläre Abfrage ist | |
| $[?count(@.*) == 1] | wohlgetypt |
| $[?count(1) == 1] | nicht wohlgetypt, da 1 keine Abfrage oder |
| Funktionsausdruck ist | |
| $[?count(foo(@.*)) | wohlgetypt, wobei foo() eine Funktions- |
| == 1] | erweiterung mit Parameter vom Typ |
| NodesType und Ergebnistyp NodesType ist | |
| $[?match(@.timezone, | wohlgetypt |
| 'Europe/.*')] | |
| $[?match(@.timezone, | nicht wohlgetypt, da LogicalType nicht in |
| 'Europe/.*') == | Vergleichen verwendet werden darf |
| true] | |
| $[?value(@..color) | wohlgetypt |
| == "red"] | |
| $[?value(@..color)] | nicht wohlgetypt, da ValueType nicht in |
| einem Testausdruck verwendet werden darf | |
| $[?bar(@.a)] | wohlgetypt für jede Funktion bar() mit |
| Parameter beliebigen deklarierten Typs und | |
| Ergebnistyp LogicalType | |
| $[?bnl(@.*)] | wohlgetypt für jede Funktion bnl() mit |
| Parameter deklariert NodesType oder | |
| LogicalType und Ergebnistyp LogicalType | |
| $[?blt(1==1)] | wohlgetypt, wobei blt() eine Funktion |
| mit Parameter deklariert LogicalType und | |
| Ergebnistyp LogicalType ist | |
| $[?blt(1)] | nicht wohlgetypt für dieselbe Funktion |
| blt(), da 1 keine Abfrage, kein logical- | |
| expr und kein Funktionsausdruck ist | |
| $[?bal(1)] | wohlgetypt, wobei bal() eine Funktion |
| mit Parameter deklariert ValueType und | |
| Ergebnistyp LogicalType ist |
Tabelle 14: Beispiele Funktionsausdrücke