On suppose que tu connais la syntaxe et les types de données JSON.
jq fonctionne en faisant passer les données JSON entrantes à travers une expression unique (écrite sous la forme d'un enchaînement de filtres) pour obtenir les données transformées souhaitées.
Le langage jq est implémenté par le programme jq.
Ce programme fournit plusieurs options en ligne de commande bien pratiques pour contrôler la façon dont l'entrée est consommée et dont la sortie est présentée.
Dans les exemples ci-dessous, tu rencontreras :
-n ou --null-input
Normalement, on donne au programme jq un fichier à lire, ou bien on lui envoie des données sur son entrée.
L'option --null-input permet de générer des données JSON sans aucune entrée.
-c ou --compact-output
Par défaut, jq met en forme sa sortie de manière lisible.
C'est extrêmement utile pour les humains de voir les données bien formatées.
En revanche, ce n'est pas nécessaire pour les machines : l'option --compact-output supprime les espaces de formatage afin de réduire la taille du JSON obtenu.
-f filename ou --from-file filename
Lire le programme jq depuis filename au lieu de le fournir sur la ligne de commande.
sed et awk utilisent tous les deux l'option -f dans le même but.
Tu verras cette option utilisée dans les scripts de test des exercices d'entraînement.
La suite de cette leçon se concentrera sur le langage jq.
Les filtres sont aussi appelés expressions.
Un filtre prend une entrée et produit une sortie.
Comme dans un shell Unix, on peut relier des filtres avec un tube | pour connecter la sortie d'un filtre à l'entrée d'un autre.
.
C'est le filtre le plus simple. Il transmet simplement son entrée à sa sortie.
$ echo '[1, 2, 3]' | jq '.'
[
1,
2,
3
]
Voici une introduction rapide à la manipulation des tableaux. On verra ce sujet plus en détail plus loin.
On accède aux éléments d'un tableau avec des crochets, et l'indexation commence à zéro.
$ echo '[10, 20, 30]' | jq '.[1]'
20
Un filtre peut construire un tableau en entourant une expression de [ et ]
avec une liste connue d'éléments :
jq -n '[1, 2, 3]'
pour rassembler un flux d'éléments : par exemple, range est une fonction qui produit un flux de nombres
$ jq -n 'range(10; 70; 15)'
10
25
40
55
L'utilisation de [] rassemble les résultats de l'expression dans un tableau
$ jq -c -n '[range(10; 70; 15)]'
[10,25,40,55]
La virgule n'est pas seulement une syntaxe qui sépare les éléments d'un tableau. La virgule est un opérateur qui assemble des flux.
Par exemple, [1, 2, 3] est un filtre qui utilise le constructeur de tableau [] pour rassembler le résultat de l'assemblage des trois expressions 1, 2 et 3.
Tu as remarqué les points-virgules dans range(10; 70; 15) ci-dessus ?
Comme les virgules ont un rôle spécifique dans le langage jq, les fonctions qui prennent plusieurs arguments utilisent des points-virgules pour séparer les arguments.
Une introduction rapide aux objets.
Comme dans beaucoup de langages de programmation, on utilise des points pour accéder aux propriétés d'un objet
$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
On peut aussi utiliser des crochets pour les objets, mais il faut alors des guillemets pour les littéraux string. C'est une façon de travailler avec des clés contenant des espaces.
$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"
Tu peux construire un objet avec {} et des paires key: value.
Les guillemets ne sont pas nécessaires autour des clés qui sont des strings « simples ».
jq -n '{question: (6 * 9), answer: 42}'
produit
{
"question": 54,
"answer": 42
}
Pour traiter la clé comme une expression, il faut l'entourer de parenthèses (l'exemple suivant produit lui aussi le même résultat que ci-dessus).
echo '[{"key":"question", "value":54}, {"key":"answer", "value":42}]' \
| jq '{(.[0].key): .[0].value, (.[1].key): .[1].value}'
Par exemple, avec un fichier file.json contenant
{
"key1": "value1",
"key2": [5, 15, 25]
}
Calculons la longueur du tableau key2 :
$ jq '.key2 | length' file.json
3
On envoie la sortie de l'expression .key2 en entrée de length, qui, sans surprise, produit le nombre d'éléments du tableau.
Dans cet exemple, les données JSON d'entrée sont ignorées et n'ont aucun impact sur la sortie :
$ echo '{"answer": 42}' | jq '6 * 9'
54
Un filtre peut produire plusieurs valeurs.
Par exemple, le filtre .[] produit chaque élément d'un tableau comme une valeur distincte :
$ jq -n -c '[1, 2, 3]'
[1,2,3]
$ jq -n -c '[1, 2, 3] | .[]'
1
2
3
En enchaînant un tel filtre avec un autre, le deuxième filtre sera exécuté pour chaque valeur :
$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6
C'est une sorte d'itération implicite.
Une fois que tu as compris cette technique, tu réalises que des filtres jq très puissants peuvent être très concis.
Les parenthèses servent à regrouper des sous-expressions pour imposer l'ordre des opérations, comme dans d'autres langages.
En jq, le besoin de parenthèses peut sembler un peu surprenant.
Par exemple, imaginons que l'on veuille construire un tableau à 2 éléments : la racine carrée de 9, et e élevé à la puissance 1.
Les deux expressions individuelles sont 9 | sqrt et 1 | exp.
On s'attend à ce que la sortie soit le tableau [3, 2.7...]
$ jq -n '[ 9|sqrt, 1|exp ]'
[
20.085536923187668,
2.718281828459045
]
Pourquoi n'a-t-on pas obtenu ce qu'on attendait ? jq interprète cela comme ceci :
[ ((9|sqrt), 1) | exp ]
jq construit un flux de deux éléments (3 et 1) qui sont chacun donnés à exp.
Il faut s'assurer que exp ne prend qu'un seul nombre en entrée.
Autrement dit, il faut imposer que le tube soit évalué avant la virgule.
$ jq -n '[ 9|sqrt, (1|exp) ]'
[
3,
2.718281828459045
]
Sans entrer dans les détails (les fonctions feront l'objet d'un autre exercice), voici quelques fonctions intégrées utiles :
length
Étant donné un tableau en entrée, produit le nombre d'éléments du tableau.
$ jq -n '[10, 20, 30, 40] | length'
4
+
Cet opérateur fait des choses différentes selon le type de ses opérandes : il additionne des nombres, il concatène des strings, il ajoute des tableaux, il fusionne des objets.
$ jq -c -n '
3 + 4,
"foo" + "bar",
["a", "b"] + ["c"],
{"m": 10} + {"n": 20}
'
7
"foobar"
["a","b","c"]
{"m":10,"n":20}
add est une fonction qui prend un tableau et renvoie un élément obtenu en additionnant tous les éléments selon les règles de +.
[1, 2, 3] | add produit 6.
map
Étant donné un tableau en entrée et un filtre en argument, produit un tableau où le filtre est appliqué à chaque élément
$ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
[2,4,6,8]
select
Étant donné une entrée et un filtre en argument :
null, vraiment aucune sortie)Par exemple, étant donné quelques nombres, on sélectionne ceux qui sont divisibles par 3
$ jq -n 'range(10) | select(. % 3 == 0)'
0
3
6
9
Rappelle-toi que range produit un flux de nombres.
select sera appelé une fois pour chaque nombre.
Seuls les nombres qui « passent » l'expression sont produits.
On a souvent besoin de sélectionner des éléments d'un tableau. Il y a plusieurs façons de procéder.
Avec l'entrée ["Anne", "Bob", "Cathy", "Dave"], sélectionne les noms de longueur 4.
utilise map et select ensemble
map(select(length == 4))
éclate le tableau en éléments, applique select sur ce flux, puis rassemble les résultats
[ .[] | select(length == 4) ]
Les commentaires commencent par le caractère # et se poursuivent jusqu'à la fin de la ligne.
Tu as soudain une envie de pancakes. En tant que personne moderne à l’esprit technique, tu écris une liste de courses pour les ingrédients des pancakes au format JSON. La structure de la liste est :
{
"name": "name of shopping list",
"ingredients": [ ...list of ingredients... ],
"optional ingredients": [ ...list of ingredients... ]
}
Un ingrédient est représenté par un objet JSON, comme ceci :
{
"item": "flour",
"amount": {
"quantity": 2,
"unit": "cup"
}
}
Un ingrédient possède une propriété facultative nommée "substitute" qui contient une string désignant un autre ingrédient pouvant être utilisé à la place.
Voyons comment on peut examiner la liste de courses avec jq
Écris une expression qui produit l’élément "name" de la liste de courses.
Ne compte que les ingrédients requis. N’inclus pas les ingrédients facultatifs.
Écris une expression qui produit la quantité de sucre. Seule la partie numérique est demandée.
Certains ingrédients peuvent être remplacés (si tu n’as pas l’ingrédient X, tu peux utiliser Y). Produis un objet JSON qui associe l’ingrédient recommandé à son substitut. Inclus les ingrédients facultatifs dans l’association.
Inscris-toi sur Exercism pour apprendre et maîtriser jq avec 12 concepts75 exercices, et un vrai mentorat humain, le tout gratuitement.