Un oggetto JSON è, per usare la terminologia di altri linguaggi, un «hash», una «map» o un «dictionary».
JSON definisce un oggetto così:
Un oggetto è un insieme non ordinato di coppie nome/valore. Un oggetto inizia con
{(parentesi graffa aperta) e termina con}(parentesi graffa chiusa). Ogni nome è seguito da:(due punti) e le coppie nome/valore sono separate da,(virgola).
Il nome deve essere una stringa. Un altro termine per nome è chiave.
Il valore può essere di qualsiasi tipo JSON. Valori diversi nello stesso oggetto possono essere di tipi diversi, come in questo esempio.
{
"name": "Jane",
"age": 42,
"pets": ["cat", "fish"],
"address": {"street": "123 Main St", "city": "Springfield"}
}
Nota che non deve esserci una virgola dopo l'ultima coppia chiave-valore.
Usa le parentesi graffe per raccogliere le coppie nome/valore. Anche se i nomi devono essere stringhe, non è necessario racchiuderli tra virgolette se sono simili a identificatori (composti da caratteri alfanumerici e underscore, e non iniziano con una cifra).
{name: "Jane", age: 42}
È valido usare chiavi che non sono simili a identificatori. Basta racchiuderle tra virgolette.
{"first name": "Jane", "last name": "Lopez", age: 42}
Se il nome è il risultato di un'espressione, l'espressione deve essere tra parentesi.
$ echo "Jane" | jq -Rc '{.: 42}'
jq: error: syntax error, unexpected '.' (Unix shell quoting issues?) at <top-level>, line 1:
{.: 42}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
{.: 42}
jq: 2 compile errors
$ echo "Jane" | jq -Rc '{(.): 42}'
{"Jane":42}
Un paio di casi frequenti nella costruzione di oggetti hanno una sintassi abbreviata.
Riutilizzare coppie chiave-valore da un oggetto di input.
$ jq -n '$ENV | {USER: .USER, EDITOR: .EDITOR}'
{
"USER": "glennj",
"EDITOR": "vim"
}
$ENV è un oggetto che contiene le coppie nome-valore dell'ambiente.
Le ripetitive coppie key: .key si possono scrivere semplicemente come key
$ jq -n '$ENV | {USER, EDITOR}'
{
"USER": "glennj",
"EDITOR": "vim"
}
Allo stesso modo, esiste una forma abbreviata quando si usano le variabili.
$ jq -cn '"foo" as $a | "bar" as $b | {a: $a, b: $b}'
{"a":"foo","b":"bar"}
$ jq -cn '"foo" as $a | "bar" as $b | {$a, $b}'
{"a":"foo","b":"bar"}
I valori si recuperano da un oggetto con la notazione con il punto.
{name: "Jane", age: 42} | .age # => 42
Se non puoi fare riferimento alla chiave come a un identificatore, usa la notazione con le parentesi.
"name" as $key | {name: "Jane", age: 42} | .$key # => error
"name" as $key | {name: "Jane", age: 42} | .[$key] # => "Jane"
Se la chiave non è presente nell'oggetto, il risultato è null.
{name: "Jane", age: 42} | .sport # => null
Scoprirai che questa è un'azione che devi ripetere più e più volte quando analizzi i risultati delle query API.
Dato un oggetto che contiene valori di tipo array o oggetto, possiamo «concatenare» tra loro le espressioni di indicizzazione.
{
"name": "Jane",
"age": 42,
"pets": ["cat", "fish"],
"address": {"street": "123 Main St", "city": "Springfield"}
}
| (
.pets[1], # => "fish"
.address.city # => "Springfield"
)
Per aggiungere una nuova coppia chiave-valore a un array, o per aggiornare il valore di una chiave esistente, usa l'operatore di assegnazione =, con un'espressione di indicizzazione sul lato sinistro.
{name: "Jane", age: 42} | .sport = "tennis" | .age = 21
# => {
# "name": "Jane",
# "age": 21,
# "sport": "tennis"
# }
L'operatore + unisce gli oggetti.
{Richard: 54} + {Jane: 42}
# => {
# "Richard": 54,
# "Jane": 42
# }
Usa la funzione del per rimuovere una chiave.
Restituisce l'oggetto aggiornato.
{name: "Jane", age: 42} | del(.age) # => {"name": "Jane"}
Il parametro di del è un'espressione di indicizzazione (che usa la notazione con il punto o con le parentesi) che si risolve in una chiave dell'oggetto.
jq la chiama espressione di percorso.
Non basta fornire una semplice stringa.
{name: "Jane", age: 42} | del(name) # error: name/0 is not defined
{name: "Jane", age: 42} | del("name") # error: Invalid path expression with result "name"
{name: "Jane", age: 42} | del(.name) # OK
{name: "Jane", age: 42} | del(.["name"]) # OK
Per verificare se l'oggetto ha una chiave, usa la funzione has.
{name: "Jane", age: 42} as $example
|
($example | has("name")), # => true
($example | has("sport")) # => false
Verifica se una chiave è presente in un oggetto con in.
{name: "Jane", age: 42} as $example
|
("name" | in($example)), # => true
("sport" | in($example)) # => false
Usa la funzione keys per produrre un elenco di tutte le chiavi.
{name: "Jane", age: 42} | keys # => ["age", "name"]
Nota che keys ordina le chiavi.
Per recuperare le chiavi nell'ordine originale, usa keys_unsorted.
Non esiste una funzione equivalente per elencare tutti i valori.
Tuttavia il filtro .[] restituisce i valori dell'oggetto come flusso, e quel flusso può essere catturato con il costruttore di array [...].
[{first: "Jane", last: "Lopez", status: "awesome!"} | .[]]
# => ["Jane", "Lopez", "awesome!"]
La funzione map_values(filter) applica il filtro a ciascun valore dell'oggetto.
{first: "Jane", last: "Lopez", status: "awesome!"}
| map_values(ascii_upcase)
# => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
Per iterare su un oggetto, dobbiamo prima convertirlo in un array di oggetti chiave-valore.
La funzione to_entries fa questo.
{name: "Jane", age: 42} | to_entries
# => [
# {
# "key": "name",
# "value": "Jane"
# },
# {
# "key": "age",
# "value": 42
# }
# ]
A questo punto, possiamo usare le funzioni di iterazione sugli array, come map.
La funzione from_entries è l'inversa: converte un array di oggetti chiave-valore in un oggetto.
[
{"key":"name", "value":"Jane"},
{"key":"age", "value":42}
] | from_entries # => {"name": "Jane", "age": 42}
Per applicare un filtro a ciascuna coppia chiave-valore di un oggetto, usa la funzione with_entries(filter).
Per esempio, dato un oggetto che associa un nome a un'età, le chiavi e i valori si possono scambiare in questo modo.
{"Jane": 42, "Richard": 54}
| with_entries({key: (.value | tostring), value: .key})
produce
{
"42": "Jane",
"54": "Richard"
}
with_entries(filter) equivale a
to_entries | map(filter) | from_entries