Chudy
jq -r '(.[0] | keys_unsorted) as $keys | $keys, map([.[ $keys[] ]])[] | @csv'
lub:
jq -r '(.[0] | keys_unsorted) as $keys | ([$keys] + map([.[ $keys[] ]])) [] | @csv'
Szczegóły
Na bok
Opisanie szczegółów jest trudne, ponieważ jq jest zorientowane strumieniowo, co oznacza, że działa na sekwencji danych JSON, a nie na pojedynczej wartości. Strumień wejściowy JSON jest konwertowany na jakiś typ wewnętrzny, który jest przepuszczany przez filtry, a następnie kodowany w strumieniu wyjściowym na końcu programu. Typ wewnętrzny nie jest modelowany przez JSON i nie istnieje jako nazwany typ. Najłatwiej to wykazać, badając dane wyjściowe samego indeksu ( .[]
) lub operatora przecinka (zbadanie tego bezpośrednio można wykonać za pomocą debugera, ale byłoby to pod względem wewnętrznych typów danych jq, a nie pojęciowych typów danych za JSON) .
$ jq -c '. []' <<< '["a", "b"]'
"za"
"b"
$ jq -cn '"a", "b"'
"za"
"b"
Zauważ, że dane wyjściowe nie są tablicą (która byłaby ["a", "b"]
). Kompaktowe dane wyjściowe ( -c
opcja) pokazują, że każdy element tablicy (lub argument ,
filtru) staje się oddzielnym obiektem w wyniku (każdy znajduje się w osobnym wierszu).
Strumień jest podobny do sekwencji JSON , ale używa znaków nowej linii zamiast RS jako separatora danych wyjściowych po zakodowaniu. W konsekwencji do tego typu wewnętrznego w tej odpowiedzi odnosi się ogólny termin „sekwencja”, przy czym „strumień” jest zarezerwowany dla zakodowanego wejścia i wyjścia.
Konstruowanie filtra
Klucze pierwszego obiektu można wyodrębnić za pomocą:
.[0] | keys_unsorted
Klucze będą zazwyczaj przechowywane w oryginalnej kolejności, ale zachowanie dokładnej kolejności nie jest gwarantowane. W związku z tym będą musiały zostać użyte do indeksowania obiektów, aby uzyskać wartości w tej samej kolejności. Zapobiegnie to również umieszczaniu wartości w niewłaściwych kolumnach, jeśli niektóre obiekty mają inną kolejność kluczy.
Aby oba wyprowadzić klucze jako pierwszy wiersz i udostępnić je do indeksowania, są one przechowywane w zmiennej. Następny etap potoku odwołuje się następnie do tej zmiennej i używa operatora przecinka, aby dołączyć nagłówek do strumienia wyjściowego.
(.[0] | keys_unsorted) as $keys | $keys, ...
Wyrażenie po przecinku jest trochę zawiłe. Operator indeksu na obiekcie może przyjąć sekwencję ciągów (np. "name", "value"
), Zwracając sekwencję wartości właściwości dla tych ciągów. $keys
jest tablicą, a nie sekwencją, więc []
jest stosowana do konwersji na sekwencję,
$keys[]
które można następnie przekazać .[]
.[ $keys[] ]
To także tworzy sekwencję, więc konstruktor tablicy jest używany do konwersji jej na tablicę.
[.[ $keys[] ]]
To wyrażenie ma być zastosowane do pojedynczego obiektu. map()
służy do zastosowania go do wszystkich obiektów w tablicy zewnętrznej:
map([.[ $keys[] ]])
Na koniec na tym etapie jest to konwertowane na sekwencję, dzięki czemu każdy element staje się oddzielnym wierszem w wyniku.
map([.[ $keys[] ]])[]
Po co pakować sekwencję w tablicę map
tylko po to, aby ją uwolnić? map
tworzy tablicę; .[ $keys[] ]
tworzy sekwencję. Zastosowanie map
do sekwencji z .[ $keys[] ]
utworzy tablicę sekwencji wartości, ale ponieważ sekwencje nie są typu JSON, więc zamiast tego otrzymasz spłaszczoną tablicę zawierającą wszystkie wartości.
["NSW","AU","state","New South Wales","AB","CA","province","Alberta","ABD","GB","council area","Aberdeenshire","AK","US","state","Alaska"]
Wartości z każdego obiektu należy przechowywać oddzielnie, aby w ostatecznym wyniku stały się oddzielnymi wierszami.
Na koniec sekwencja jest przekazywana przez @csv
formater.
Alternatywny
Elementy można oddzielić raczej późno niż wcześnie. Zamiast używać operatora przecinka, aby uzyskać sekwencję (przekazując sekwencję jako prawy operand), sekwencja nagłówka ( $keys
) może zostać umieszczona w tablicy i +
użyta do dołączenia tablicy wartości. To nadal musi zostać przekonwertowane na sekwencję przed przekazaniem do @csv
.
json2csv
jest na stackoverflow.com/questions/57242240/ ...