JMESPath pour débutants : des projections qui battent JSONPath
L’essentiel : JMESPath reforme des lots d'objets plus directement que JSONPath. Ce guide débutant couvre la syntaxe, les projections, les pipes, les fonctions intégrées et l'usage dans AWS CLI.

L'essentiel : utilisez JSON Pointer pour localiser par position, JSONPath pour filtrer ou récurser, et JMESPath quand il faut reformer le résultat ou le projeter en ligne de commande ; un seul champ connu n'a besoin d'aucun des trois.
Si votre objectif est de reformer un lot d'objets en une autre forme, JMESPath est souvent plus direct que JSONPath. Il ne cherche pas des nœuds : il construit un résultat.
1. Qu'est-ce que JMESPath
JMESPath est un langage de requête conçu spécifiquement pour JSON. Il a été créé à l'origine pour filtrer la sortie d'AWS CLI, puis s'est répandu dans de nombreux langages via des implémentations comme jmespath.js, jmespath.py et go-jmespath. Son objectif diffère de celui de JSONPath :
- JSONPath se concentre sur la sélection d'un ensemble de nœuds par chemin et condition, et renvoie un ensemble de nœuds ;
- JMESPath se concentre sur la transformation du JSON d'entrée et renvoie une valeur de forme quelconque.
Cette différence rend JMESPath particulièrement adapté aux projections de listes, au renommage de champs et au rognage de résultats, par exemple réduire vingt champs d'une réponse d'API aux trois champs dont le frontend a réellement besoin. Si vous n'avez pas encore lu les bases de JSONPath, commencez par Le langage de requête JSONPath en pratique.
2. Syntaxe de base : des identifiants aux indices
JMESPath utilise moins de symboles que JSONPath et se lit davantage comme une expression d'extraction :
| Syntaxe | Signification | Exemple |
|---|---|---|
name |
Accéder à un membre d'objet | people |
a.b |
Accéder à des membres imbriqués | store.bicycle.color |
[0] |
Accéder à un index de tableau | people[0] |
[-1] |
Accéder au dernier élément | people[-1] |
[0:2] |
Tranche, début inclus et fin exclue | people[0:2] |
[*] |
Projection de liste | people[*].name |
[] |
Projection aplatie | people[].tags[] |
[?condition] |
Projection filtrée | people[?age > 18] |
{key: expr} |
Hachage multi-sélection | {name: name, age: age} |
[expr, expr] |
Liste multi-sélection | [name, age] |
| |
Envoyer le résultat gauche vers la droite | people[*].age | [0] |
Un exemple minimal :
{
"people": [
{ "name": "Alice", "age": 31, "city": "Shanghai" },
{ "name": "Bob", "age": 17, "city": "Beijing" }
]
}
people[0].name → "Alice"
people[-1].city → "Beijing"
people[0:2].name → ["Alice", "Bob"]
Notez pourquoi people[0:2].name renvoie un tableau : une tranche renvoie une liste, et le .name qui suit est automatiquement projeté sur chaque élément de cette liste. C'est la plus grande différence entre JMESPath et l'accès ordinaire aux objets.
3. Projections : transformer une liste en une autre
Une projection est le concept central de JMESPath. Elle fonctionne en deux étapes : évaluer chaque élément d'une liste, puis collecter les résultats dans une nouvelle liste. Les éléments qui s'évaluent à null sont supprimés automatiquement.
people[*].name // ["Alice", "Bob"]
people[*].{name: name, age: age} // a list of objects
people[?age > 18].name // ["Alice"]
La deuxième ligne est une expression de projection typique : people[*].{name: name, age: age}. Elle reconstruit chaque élément en { "name": ..., "age": ... } et abandonne le champ city superflu. Comparé à JSONPath, qui vous donne des nœuds que vous mappez ensuite dans le code, cela économise une boucle.
Deux types de projections méritent d'être distingués :
[*]préserve la structure de liste originale et saute les valeurs nulles ;[]est une projection aplatie qui réduit d'abord un niveau de listes imbriquées, ce qui convient aux expressions commepeople[].tags[]qui veulent « tous les tags de toutes les personnes ».
4. Pipes et multi-sélection
Le pipe | signifie « arrêter la projection courante et traiter le résultat comme une nouvelle entrée ». Son usage le plus courant est de prendre un index après une projection :
people[*].name | [0] → "Alice"
people[*].age | sort(@) | [-1] → the maximum age
Sans le pipe, people[*].name[0] est interprété comme prendre le premier caractère de chaque nom, ce qui n'est pas ce que vous voulez. Le pipe est le symbole le plus facile à oublier et le plus utile de JMESPath.
Il existe deux formes de multi-sélection :
// Multi-select hash: the result is an object
people[0].{name: name, age: age}
// Multi-select list: the result is an array
people[0].[name, age]
Les hachages multi-sélection servent à construire des résultats nommés, tandis que les listes multi-sélection servent à une consommation positionnelle. Les deux peuvent être imbriqués dans des projections, mais attention : dans un hachage multi-sélection, une clé dont la valeur est null est conservée, alors qu'une projection supprime tout l'élément null.
5. Fonctions intégrées
La norme JMESPath définit un ensemble de fonctions. Les plus courantes :
| Fonction | Rôle | Exemple |
|---|---|---|
length() |
Obtenir la longueur | length(people) |
sort() |
Trier des valeurs | sort(people[*].age) |
sort_by() |
Trier selon un champ | sort_by(people, &age) |
max() / min() |
Maximum / minimum | max(people[*].age) |
sum() |
Sommer des valeurs | sum(people[*].age) |
keys() |
Obtenir les clés d'un objet | keys(people[0]) |
contains() |
Vérifier la présence | contains(name, "Ali") |
to_string() |
Convertir en chaîne | to_string(age) |
Le deuxième argument de sort_by est une expression &, qui signifie « prendre ce champ de chaque élément » :
sort_by(people, &age)[*].name
Ces fonctions permettent à JMESPath de faire une agrégation simple, alors que JSONPath est uniquement conçu pour la sélection ; sommer et regrouper exigent généralement jq ou du code.
6. Comparaison directe avec JSONPath
| Dimension | JSONPath | JMESPath |
|---|---|---|
| Objectif principal | Sélectionner des nœuds | Transformer des données |
| Symbole racine | $ |
Aucun ; écrire directement les noms de champs |
| Nœud courant | @ |
@ (seulement dans les arguments de fonction) |
| Filtre | [?(@.age > 18)] |
[?age > 18] |
| Joker | [*] |
[*] ou [] |
| Construire de nouveaux objets | Non pris en charge | {name: name} |
| Pipes | Non pris en charge | | |
| Norme | RFC 9535 | Spécification JMESPath |
Un guide de décision en une phrase :
- Utilisez JSONPath quand vous avez seulement besoin de trouver des nœuds correspondant à une condition ;
- Utilisez JMESPath quand il faut reformer le résultat en ce que le frontend attend ;
- N'utilisez ni l'un ni l'autre pour lire un seul champ connu ; accédez directement à la propriété.
Si le résultat de la requête doit être réécrit dans le document, aucun des deux langages ne convient. Utilisez JSON Pointer et les patchs ; voir JSON Pointer, Patch et Merge Patch.
7. JMESPath dans AWS CLI
Le paramètre --query d'AWS CLI est du JMESPath, ce qui en constitue l'usage le plus répandu :
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{Id: InstanceId, State: State.Name, Type: InstanceType}' \
--output table
Cette commande fait trois choses : elle aplatit deux listes imbriquées avec [], ne garde que trois champs avec un hachage multi-sélection, et rend le résultat sous forme de table avec --output table. Avec JSONPath, il faudrait plus de niveaux et on n'obtiendrait pas l'effet « renommer plus rogner ».
Autres formes courantes :
# Only running instances
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,PublicIpAddress]'
# The value of the Name tag
aws ec2 describe-instances --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value[]'
Remarquez que les accents graves encadrent des littéraux, pas des chaînes. Dans AWS CLI, les chaînes utilisent des guillemets simples et les littéraux JSON des accents graves. Cette différence est l'une des erreurs de débutant les plus courantes.
8. Erreurs courantes
- Confondre
[*]et[]: le premier préserve l'imbrication, le second aplatit un niveau, et les structures résultantes sont complètement différentes ; - Oublier le pipe :
people[*].name[0]prend le premier caractère de chaque nom, pas le premier nom ; - Écrire
@dans un filtre : les filtres JMESPath utilisent directement les noms de champs, donc[?@.age > 18]est faux ; - Traiter
nullcomme une chaîne vide : les projections supprimentnull, mais les hachages multi-sélection conservent la clé ; - Utiliser des guillemets doubles autour des littéraux dans AWS CLI : le shell les développe d'abord et réécrit l'expression.
Conseil de débogage : validez une expression sur l'entrée la plus petite possible avant de l'appliquer à des données réelles, et ajoutez --output json dans AWS CLI pour voir les résultats bruts. Pour l'édition et le formatage JSON du quotidien, l'association avec Éditeurs JSON et outils en ligne de commande rend la localisation des chemins de champs beaucoup plus rapide.
FAQ
Peut-on utiliser JMESPath et JSONPath ensemble ?
Oui, mais c'est généralement inutile. Une approche courante consiste à rogner un petit objet avec JMESPath, puis à utiliser l'accès ordinaire aux propriétés dans le code. S'il faut vraiment localiser par chemin puis modifier, JSONPath lit et JSON Pointer écrit, ce qui est une répartition plus claire.
Pourquoi people[*].name renvoie-t-il autre chose qu'une seule chaîne ?
Parce que [*] est une projection, et le résultat est toujours une liste, même s'il n'y a qu'une personne. Pour obtenir une valeur unique, ajoutez un pipe et un index : people[*].name | [0].
Que devient null dans une projection ?
Une projection de liste saute automatiquement les éléments qui s'évaluent à null, donc le résultat peut être plus court que la liste originale. Un hachage multi-sélection conserve la clé et préserve la valeur null, ce qui compte lors de la construction de réponses d'API.
JMESPath peut-il faire de l'agrégation et du regroupement ?
Il peut faire une agrégation simple avec sum(), max() et sort_by(). Le regroupement, les jointures et les fonctions de fenêtre sont hors du standard. Laissez l'analyse complexe à jq, à SQL ou à du code.
Comment choisir entre JMESPath et JSONPath ?
Utilisez JSONPath quand il faut sélectionner des nœuds par chemin et condition et recevoir un ensemble de nœuds ; utilisez JMESPath quand il faut reformer le résultat en ce que le frontend attend, avec renommage et rognage des champs. Quand vous lisez un seul champ connu, n'utilisez ni l'un ni l'autre ; accédez directement à la propriété.
Faut-il utiliser un pipe pour prendre la première valeur projetée ?
Oui. people[*].name est une projection, donc le résultat est toujours une liste ; sans pipe, people[*].name[0] prend le premier caractère de chaque nom. Écrivez people[*].name | [0] pour obtenir la première valeur.