Aller au contenu principal

2.4. Function Extensions (Extensions de fonctions)

2.4. Function Extensions (Extensions de fonctions)

Au-delà de la fonctionnalité d'expression de filtre définie dans les sous-sections précédentes, JSONPath définit un point d'extension utilisable pour ajouter de la fonctionnalité d'expression de filtre : les « Function Extensions » (extensions de fonctions).

Cette section définit le point d'extension et certaines extensions de fonctions qui l'utilisent. Bien que ces mécanismes soient conçus pour employer le point d'extension, ils font partie intégrante de la spécification JSONPath et sont censés être implémentés comme toute autre partie intégrante de cette spécification.

Une extension de fonction définit un nom enregistré (voir la section 3.2) applicable à une séquence de zéro ou plusieurs arguments, produisant un résultat. Chaque nom de fonction enregistré est unique.

Une extension de fonction DOIT être définie de sorte que son évaluation soit sans effet de bord, c'est-à-dire que tous les ordres d'évaluation possibles et les choix de court-circuit ou d'évaluation complète d'une expression la contenant DOIVENT mener au même résultat. (Note : La mémoïsation ou la journalisation ne sont pas des effets de bord en ce sens car elles ne sont visibles qu'au niveau implémentation — elles n'influencent pas le résultat de l'évaluation.)

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 /
logical-expr /
function-expr

Toute expression de fonction dans une requête doit être bien formée (en se conformant à l'ABNF ci-dessus) et bien typée ; sinon, l'implémentation JSONPath DOIT lever une erreur (voir la section 2.1). Pour définir quelles expressions de fonction sont bien typées, on introduit d'abord un système de types.

2.4.1. Type System for Function Expressions (Système de types pour les expressions de fonction)

Chaque paramètre et le résultat d'une extension de fonction doivent avoir un type déclaré.

Les types déclarés permettent de vérifier qu'une requête JSONPath est bien typée indépendamment de tout argument de requête auquel la requête JSONPath est appliquée.

Le tableau 13 définit les types disponibles en termes d'instances qu'ils contiennent.

TypeInstances
ValueTypevaleurs JSON ou Nothing
LogicalTypeLogicalTrue ou LogicalFalse
NodesTypeNodelists

Tableau 13 : Système de types des extensions de fonction

Notes :

  • Les seules instances directement représentables dans la syntaxe JSONPath sont certaines valeurs JSON dans ValueType exprimées comme littéraux (qui, en JSONPath, sont limitées aux valeurs primitives).

  • Le résultat spécial Nothing représente l'absence d'une valeur JSON et est distinct de toute valeur JSON, y compris null.

  • LogicalTrue et LogicalFalse ne sont pas liés aux valeurs JSON exprimées par les littéraux true et false.

2.4.2. Type Conversion (Conversion de types)

Comme les requêtes peuvent être utilisées dans des expressions logiques en testant l'existence d'au moins un nœud (section 2.3.5.2.1), une expression de fonction de type déclaré NodesType peut servir d'argument de fonction pour un paramètre de type déclaré LogicalType, avec la règle de conversion équivalente :

  • Si la nodelist contient un ou plusieurs nœuds, le résultat de la conversion est LogicalTrue.

  • Si la nodelist est vide, le résultat de la conversion est LogicalFalse.

Notes :

  • L'extraction d'une valeur d'une nodelist peut se faire de plusieurs manières, donc une conversion implicite de NodesType vers ValueType pourrait surprendre et n'a pas été définie.

  • Une expression de fonction de type déclaré NodesType peut indirectement servir d'argument pour un paramètre de type déclaré ValueType en enveloppant l'expression dans un appel à une extension de fonction, telle que value() (voir la section 2.4.8), qui prend un paramètre de type NodesType et renvoie un résultat de type ValueType.

Le caractère bien typé des expressions de fonction peut maintenant être défini en termes de ce système de types.

2.4.3. Well-Typedness of Function Expressions (Bien-typage des expressions de fonction)

Pour qu'une expression de fonction soit bien typée :

  1. Son type déclaré doit être bien typé dans le contexte où elle apparaît.

Selon la grammaire, une expression de fonction peut apparaître dans trois contextes immédiats différents, qui mènent aux conditions de bien-typage suivantes :

Comme test-expr dans une expression logique : le type de résultat déclaré de la fonction est LogicalType ou (donnant lieu à une conversion selon la section 2.4.2) NodesType.

Comme comparable dans une comparaison : le type de résultat déclaré de la fonction est ValueType.

Comme function-argument dans une autre expression de fonction : le type de résultat déclaré satisfait les règles suivantes pour le paramètre correspondant de la fonction englobante.

  1. Ses arguments doivent être bien typés pour le type déclaré des paramètres correspondants.

Les arguments de l'expression de fonction sont bien typés lorsque chaque argument peut être utilisé pour le type déclaré du paramètre correspondant, selon l'une des conditions suivantes :

  • Lorsque l'argument est une expression de fonction avec le même type de résultat déclaré que le type déclaré du paramètre.

  • Lorsque le type déclaré du paramètre est LogicalType et que l'argument est l'un des suivants :

    • Une expression de fonction de type de résultat déclaré NodesType. Dans ce cas, l'argument est converti en LogicalType selon la section 2.4.2.

    • Une logical-expr qui n'est pas une expression de fonction.

  • Lorsque le type déclaré du paramètre est NodesType et que l'argument est une requête (qui inclut une requête singulière).

  • Lorsque le type déclaré du paramètre est ValueType et que l'argument est l'un des suivants :

    • Une valeur exprimée comme littéral.

    • Une requête singulière. Dans ce cas :

      • Si la requête aboutit à une nodelist d'un seul nœud, l'argument est la valeur du nœud.

      • Si la requête aboutit à une nodelist vide, l'argument est le résultat spécial Nothing.

2.4.4. length() Function Extension (Extension length())

Paramètres : 1. ValueType

Résultat : ValueType (entier non signé ou Nothing)

L'extension de fonction length() fournit un moyen de calculer la longueur d'une valeur et de la rendre disponible pour un traitement ultérieur dans l'expression de filtre :

$[?length(@.authors) >= 5]

Son seul argument est une instance de ValueType (éventuellement issue d'une requête singulière, comme dans l'exemple ci-dessus). Le résultat est aussi une instance de ValueType : un entier non signé ou le résultat spécial Nothing.

  • Si la valeur d'argument est une chaîne, le résultat est le nombre de valeurs scalaires Unicode dans la chaîne.

  • Si la valeur d'argument est un tableau, le résultat est le nombre d'éléments dans le tableau.

  • Si la valeur d'argument est un objet, le résultat est le nombre de membres dans l'objet.

  • Pour toute autre valeur d'argument, le résultat est le résultat spécial Nothing.

2.4.5. count() Function Extension (Extension count())

Paramètres : 1. NodesType

Résultat : ValueType (entier non signé)

L'extension de fonction count() fournit un moyen d'obtenir le nombre de nœuds dans une nodelist et de le rendre disponible pour un traitement ultérieur dans l'expression de filtre :

$[?count(@.*.author) >= 5]

Son seul argument est une nodelist. Le résultat est une valeur (entier non signé) donnant le nombre de nœuds dans la nodelist.

Notes :

  • Il n'y a pas de déduplication de la nodelist.

  • Le nombre de nœuds dans la nodelist est compté indépendamment de leurs valeurs ou des enfants qu'ils peuvent avoir, par ex. le count d'une nodelist singulière non vide telle que count(@) vaut toujours 1.

2.4.6. match() Function Extension (Extension match())

Paramètres : 1. ValueType (chaîne)

  1. ValueType (chaîne conforme à [RFC9485])

Résultat : LogicalType

L'extension de fonction match() fournit un moyen de vérifier si (l'intégralité de ; voir la section 2.4.7) une chaîne donnée correspond à une expression régulière donnée, sous la forme décrite dans [RFC9485].

$[?match(@.date, "1974-05-..")]

Ses arguments sont des instances de ValueType (éventuellement issues d'une requête singulière, comme pour le premier argument dans l'exemple ci-dessus). Si le premier argument n'est pas une chaîne ou si le second n'est pas une chaîne conforme à [RFC9485], le résultat est LogicalFalse. Sinon, la chaîne qui est le premier argument est comparée à l'I-Regexp contenue dans la chaîne qui est le second argument ; le résultat est LogicalTrue si la chaîne correspond à l'I-Regexp et LogicalFalse sinon.

Paramètres : 1. ValueType (chaîne)

  1. ValueType (chaîne conforme à [RFC9485])

Résultat : LogicalType

L'extension de fonction search() fournit un moyen de vérifier si une chaîne donnée contient une sous-chaîne qui correspond à une expression régulière donnée, sous la forme décrite dans [RFC9485].

$[?search(@.author, "[BR]ob")]

Ses arguments sont des instances de ValueType (éventuellement issues d'une requête singulière, comme pour le premier argument dans l'exemple ci-dessus). Si le premier argument n'est pas une chaîne ou si le second n'est pas une chaîne conforme à [RFC9485], le résultat est LogicalFalse. Sinon, la chaîne qui est le premier argument est fouillée pour une sous-chaîne correspondant à l'I-Regexp contenue dans la chaîne qui est le second argument ; le résultat est LogicalTrue si au moins une telle sous-chaîne existe et LogicalFalse sinon.

2.4.8. value() Function Extension (Extension value())

Paramètres : 1. NodesType

Résultat : ValueType

L'extension de fonction value() fournit un moyen de convertir une instance de NodesType en valeur et de la rendre disponible pour un traitement ultérieur dans l'expression de filtre :

$[?value(@..color) == "red"]

Son seul argument est une instance de NodesType (éventuellement issue d'un filter-query, comme dans l'exemple ci-dessus). Le résultat est une instance de ValueType.

  • Si l'argument contient un seul nœud, le résultat est la valeur du nœud.

  • Si l'argument est la nodelist vide ou contient plusieurs nœuds, le résultat est Nothing.

Note : Une requête singulière peut être utilisée partout où un ValueType est attendu, donc il n'est pas nécessaire d'utiliser l'extension value() avec une requête singulière.

2.4.9. Examples (Exemples)

RequêteCommentaire
$[?length(@) < 3]bien typée
$[?length(@.*) < 3]pas bien typée car @.* est une requête non singulière
$[?count(@.*) == 1]bien typée
$[?count(1) == 1]pas bien typée car 1 n'est ni requête ni expression de fonction
$[?count(foo(@.*))bien typée, où foo() est une extension avec
== 1]un paramètre de type NodesType et résultat NodesType
$[?match(@.timezone,bien typée
'Europe/.*')]
$[?match(@.timezone,pas bien typée car LogicalType ne peut pas être
'Europe/.*') ==utilisé dans des comparaisons
true]
$[?value(@..color)bien typée
== "red"]
$[?value(@..color)]pas bien typée car ValueType ne peut pas être
utilisée dans une expression de test
$[?bar(@.a)]bien typée pour toute fonction bar() avec un
paramètre de tout type déclaré et résultat LogicalType
$[?bnl(@.*)]bien typée pour toute fonction bnl() avec un
paramètre NodesType ou LogicalType et résultat LogicalType
$[?blt(1==1)]bien typée, où blt() a un paramètre LogicalType
et résultat LogicalType
$[?blt(1)]pas bien typée pour la même blt(), car 1 n'est pas
requête, logical-expr ni expression de fonction
$[?bal(1)]bien typée, où bal() a un paramètre ValueType
et résultat LogicalType

Tableau 14 : Exemples d'expressions de fonction