Menggunakan jq , bagaimana JSON yang menyandikan larik objek dangkal dapat dikonversi ke CSV?
Ada banyak Tanya Jawab di situs ini yang membahas model data tertentu yang melakukan hard-code pada kolom tersebut, tetapi jawaban atas pertanyaan ini akan berfungsi jika diberikan JSON apa pun, dengan satu-satunya batasan bahwa itu adalah array objek dengan properti skalar (tidak ada deep / complex / sub-objek, karena meratakan ini adalah pertanyaan lain). Hasilnya harus berisi baris tajuk yang memberi nama bidang. Preferensi akan diberikan pada jawaban yang mempertahankan urutan bidang objek pertama, tetapi ini bukan persyaratan. Hasil mungkin menyertakan semua sel dengan tanda kutip ganda, atau hanya menyertakan yang memerlukan kutipan (mis. 'A, b').
Contoh
Memasukkan:
[ {"code": "NSW", "name": "New South Wales", "level":"state", "country": "AU"}, {"code": "AB", "name": "Alberta", "level":"province", "country": "CA"}, {"code": "ABD", "name": "Aberdeenshire", "level":"council area", "country": "GB"}, {"code": "AK", "name": "Alaska", "level":"state", "country": "US"} ]
Output yang memungkinkan:
code,name,level,country NSW,New South Wales,state,AU AB,Alberta,province,CA ABD,Aberdeenshire,council area,GB AK,Alaska,state,US
Output yang memungkinkan:
"code","name","level","country" "NSW","New South Wales","state","AU" "AB","Alberta","province","CA" "ABD","Aberdeenshire","council area","GB" "AK","Alaska","state","US"
Memasukkan:
[ {"name": "bang", "value": "!", "level": 0}, {"name": "letters", "value": "a,b,c", "level": 0}, {"name": "letters", "value": "x,y,z", "level": 1}, {"name": "bang", "value": "\"!\"", "level": 1} ]
Output yang memungkinkan:
name,value,level bang,!,0 letters,"a,b,c",0 letters,"x,y,z",1 bang,"""!""",0
Output yang memungkinkan:
"name","value","level" "bang","!","0" "letters","a,b,c","0" "letters","x,y,z","1" "bang","""!""","1"
json2csv
ada di stackoverflow.com/questions/57242240/…Jawaban:
Pertama, dapatkan larik yang berisi semua nama properti objek yang berbeda dalam masukan larik objek Anda. Itu akan menjadi kolom CSV Anda:
Kemudian, untuk setiap objek dalam input larik objek, petakan nama kolom yang Anda peroleh ke properti terkait dalam objek tersebut. Itu akan menjadi baris CSV Anda.
Terakhir, letakkan nama kolom sebelum baris, sebagai header untuk CSV, dan teruskan aliran baris yang dihasilkan ke
@csv
filter.Semua bersama Sekarang. Ingatlah untuk menggunakan
-r
bendera untuk mendapatkan hasil sebagai string mentah:sumber
$rows
tugas variabel hanya dengan membuat inline:(map(keys) | add | unique) as $cols | $cols, map(. as $row | $cols | map($row[.]))[] | @csv
$rows
tidak harus ditugaskan ke variabel; Saya hanya berpikir menugaskannya ke variabel membuat penjelasannya lebih bagus.Si Kurus
atau:
Rinciannya
Ke samping
Mendeskripsikan detailnya rumit karena jq berorientasi pada aliran, artinya ia beroperasi pada urutan data JSON, bukan pada satu nilai. Aliran JSON masukan diubah menjadi beberapa jenis internal yang dilewatkan melalui filter, kemudian dikodekan dalam aliran keluaran di akhir program. Tipe internal tidak dimodelkan oleh JSON, dan tidak ada sebagai tipe bernama. Ini paling mudah ditunjukkan dengan memeriksa output dari indeks telanjang (
.[]
) atau operator koma (memeriksanya secara langsung dapat dilakukan dengan debugger, tetapi itu akan menjadi dalam hal tipe data internal jq, daripada tipe data konseptual di belakang JSON) .Perhatikan bahwa outputnya bukan array (yang akan menjadi
["a", "b"]
). Output ringkas (-c
opsi) menunjukkan bahwa setiap elemen array (atau argumen ke,
filter) menjadi objek terpisah dalam output (masing-masing berada pada baris terpisah).Aliran seperti JSON-seq , tetapi menggunakan baris baru daripada RS sebagai pemisah keluaran saat dienkode. Akibatnya, tipe internal ini dirujuk oleh istilah umum "urutan" dalam jawaban ini, dengan "aliran" dicadangkan untuk masukan dan keluaran yang dikodekan.
Membangun Filter
Kunci objek pertama dapat diekstraksi dengan:
Biasanya kunci akan disimpan dalam urutan aslinya, tetapi urutan yang tepat tidak dijamin. Akibatnya, mereka perlu digunakan untuk mengindeks objek untuk mendapatkan nilai dalam urutan yang sama. Ini juga akan mencegah nilai berada di kolom yang salah jika beberapa objek memiliki urutan kunci yang berbeda.
Untuk mengeluarkan kedua kunci sebagai baris pertama dan membuatnya tersedia untuk pengindeksan, mereka disimpan dalam variabel. Tahap berikutnya dari pipeline kemudian mereferensikan variabel ini dan menggunakan operator koma untuk menambahkan header ke aliran keluaran.
Ekspresi setelah koma sedikit terlibat. Operator indeks pada suatu objek dapat mengambil urutan string (misalnya
"name", "value"
), mengembalikan urutan nilai properti untuk string tersebut.$keys
adalah array, bukan urutan, jadi[]
diterapkan untuk mengubahnya menjadi urutan,yang kemudian dapat diteruskan ke
.[]
Ini juga menghasilkan urutan, sehingga konstruktor array digunakan untuk mengubahnya menjadi array.
Ekspresi ini akan diterapkan ke satu objek.
map()
digunakan untuk menerapkannya ke semua objek dalam larik terluar:Terakhir untuk tahap ini, ini diubah menjadi urutan sehingga setiap item menjadi baris terpisah di keluaran.
Mengapa menggabungkan urutan menjadi array di dalam
map
satu - satunya untuk memisahkannya di luar?map
menghasilkan sebuah array;.[ $keys[] ]
menghasilkan urutan. Menerapkanmap
urutan dari.[ $keys[] ]
akan menghasilkan larik urutan nilai, tetapi karena urutan bukan tipe JSON, jadi Anda mendapatkan larik pipih yang berisi semua nilai.Nilai dari setiap objek harus dipisahkan, sehingga menjadi baris terpisah pada hasil akhir.
Akhirnya, urutan dilewatkan melalui
@csv
pemformat.Bergantian
Item dapat dipisahkan terlambat, bukan lebih awal. Alih-alih menggunakan operator koma untuk mendapatkan urutan (meneruskan urutan sebagai operan kanan), urutan header (
$keys
) bisa dibungkus dalam array, dan+
digunakan untuk menambahkan array nilai. Ini masih perlu diubah menjadi urutan sebelum diteruskan ke@csv
.sumber
keys_unsorted
alih-alihkeys
mempertahankan urutan kunci dari objek pertama?[{"a":1,"b":2,"c":3}]
.Saya membuat fungsi yang menampilkan array objek atau array ke csv dengan header. Kolom akan berada dalam urutan tajuk.
Jadi Anda bisa menggunakannya seperti ini:
sumber
Filter berikut sedikit berbeda karena akan memastikan setiap nilai diubah menjadi string. (Catatan: gunakan jq 1.5+)
Saring:
filter.jq
sumber
unique
diurutkan, sehinggaunique|sort
dapat disederhanakan menjadiunique
.-r
opsi. Jika tidak, semua tanda kutip"
menjadi extra-escaped yang bukan merupakan CSV yang valid.Varian program Santiago ini juga aman tetapi memastikan bahwa nama kunci di objek pertama digunakan sebagai tajuk kolom pertama, dalam urutan yang sama seperti yang muncul di objek itu:
sumber