Lo magro
jq -r '(.[0] | keys_unsorted) as $keys | $keys, map([.[ $keys[] ]])[] | @csv'
o:
jq -r '(.[0] | keys_unsorted) as $keys | ([$keys] + map([.[ $keys[] ]])) [] | @csv'
I dettagli
A parte
Descrivere i dettagli è complicato perché jq è orientato al flusso, il che significa che opera su una sequenza di dati JSON, piuttosto che su un singolo valore. Il flusso JSON di input viene convertito in un tipo interno che viene passato attraverso i filtri, quindi codificato in un flusso di output alla fine del programma. Il tipo interno non è modellato da JSON e non esiste come tipo denominato. È più facilmente dimostrato esaminando l'output di un semplice index ( .[]
) o dell'operatore virgola (esaminarlo direttamente potrebbe essere fatto con un debugger, ma ciò sarebbe in termini di tipi di dati interni di jq, piuttosto che i tipi di dati concettuali dietro JSON) .
$ jq -c '. []' <<< '["a", "b"]'
"un"
"b"
$ jq -cn '"a", "b"'
"un"
"b"
Nota che l'output non è un array (che sarebbe ["a", "b"]
). L'output compatto (l' -c
opzione) mostra che ogni elemento dell'array (o argomento del ,
filtro) diventa un oggetto separato nell'output (ognuno si trova su una riga separata).
Un flusso è come un JSON-seq , ma utilizza le nuove righe anziché RS come separatore di output quando codificato. Di conseguenza, questo tipo interno viene indicato con il termine generico "sequenza" in questa risposta, con "flusso" riservato per l'input e l'output codificati.
Costruire il filtro
Le chiavi del primo oggetto possono essere estratte con:
.[0] | keys_unsorted
Le chiavi vengono generalmente mantenute nell'ordine originale, ma non è garantito il mantenimento dell'ordine esatto. Di conseguenza, dovranno essere utilizzati per indicizzare gli oggetti per ottenere i valori nello stesso ordine. Ciò impedirà inoltre che i valori si trovino nelle colonne sbagliate se alcuni oggetti hanno un ordine di chiave diverso.
Per generare entrambe le chiavi come prima riga e renderle disponibili per l'indicizzazione, vengono memorizzate in una variabile. La fase successiva della pipeline fa quindi riferimento a questa variabile e utilizza l'operatore virgola per anteporre l'intestazione al flusso di output.
(.[0] | keys_unsorted) as $keys | $keys, ...
L'espressione dopo la virgola è un po 'complicata. L'operatore indice su un oggetto può accettare una sequenza di stringhe (ad esempio "name", "value"
), restituendo una sequenza di valori di proprietà per quelle stringhe. $keys
è un array, non una sequenza, quindi []
viene applicato per convertirlo in una sequenza,
$keys[]
che può quindi essere passato a .[]
.[ $keys[] ]
Anche questo produce una sequenza, quindi il costruttore di array viene utilizzato per convertirlo in un array.
[.[ $keys[] ]]
Questa espressione deve essere applicata a un singolo oggetto. map()
viene utilizzato per applicarlo a tutti gli oggetti nell'array esterno:
map([.[ $keys[] ]])
Infine, per questa fase, questo viene convertito in una sequenza in modo che ogni elemento diventi una riga separata nell'output.
map([.[ $keys[] ]])[]
Perché raggruppare la sequenza in un array all'interno map
dell'unico per separarla all'esterno? map
produce un array; .[ $keys[] ]
produce una sequenza. L'applicazione map
alla sequenza da .[ $keys[] ]
produrrebbe una matrice di sequenze di valori, ma poiché le sequenze non sono di tipo JSON, si ottiene invece una matrice appiattita contenente tutti i valori.
["NSW","AU","state","New South Wales","AB","CA","province","Alberta","ABD","GB","council area","Aberdeenshire","AK","US","state","Alaska"]
I valori di ogni oggetto devono essere tenuti separati, in modo che diventino righe separate nell'output finale.
Infine, la sequenza viene passata attraverso il @csv
formattatore.
Alternato
Gli elementi possono essere separati in ritardo, anziché in anticipo. Invece di utilizzare l'operatore virgola per ottenere una sequenza (passando una sequenza come operando a destra), la sequenza di intestazione ( $keys
) può essere racchiusa in un array e +
utilizzata per aggiungere l'array di valori. Questo deve ancora essere convertito in una sequenza prima di essere passato a @csv
.
json2csv
è su stackoverflow.com/questions/57242240/…