CSV'de değerleri çıkartmak ve biçimlendirmek için jq kullanma


57

Aşağıdaki JSON dosyasına sahibim:

{
"data": [
    {
        "displayName": "First Name",
        "rank": 1,
        "value": "VALUE"
    },
    {
        "displayName": "Last Name",
        "rank": 2,
        "value": "VALUE"
    },
    {
        "displayName": "Position",
        "rank": 3,
        "value": "VALUE"
    },
    {
        "displayName": "Company Name",
        "rank": 4,
        "value": "VALUE"
    },
    {
        "displayName": "Country",
        "rank": 5,
        "value": "VALUE"
    },
]
}

Bu biçimde bir CSV dosyasına sahip olmak istiyorum:

First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE, VALUE

Bu sadece kullanarak mümkün mü jq? Programlama becerim yok.


1
Aşağıda bir cevap verdim, ama şimdi sorunuza daha yakından bakıyorum ve merak edemiyorum - 6. DEĞER'in nereden gelmesi gerekiyor?
mikeserv


Yanıtlar:


49

jq, bir diziyi CSV dizgisine dönüştürmek için bir @csv süzgecine sahiptir. Bu filtre, alanlara gömülü virgüllerden başlayarak CSV formatıyla ilişkili karmaşıklıkların çoğunu dikkate alır. (jq 1.5, sekme ile ayrılmış değer dosyaları oluşturmak için benzer bir filtreye (@tsv) sahiptir.)

Elbette, başlıkların ve değerlerin hepsinin virgül ve çift tırnak işareti içermemesi garanti edilirse, @csv filtresini kullanmaya gerek kalmayabilir. Aksi takdirde, kullanmak muhtemelen daha iyi olur.

Örneğin, 'Şirket Adı' 'Smith, Smith ve Smith' olsaydı ve diğer değerler aşağıda gösterildiği gibi olsaydı, "-r" seçeneğiyle jq çağırmak geçerli CSV üretir:

$ jq -r '.data | map(.displayName), map(.value) | @csv' so.json2csv.json
"First Name","Last Name","Position","Company Name","Country"
"John (""Johnnie"")","Doe","Director, Planning and Posterity","Smith, Smith and Smith","Transylvania"

3
Bir şeyler jq başardı | harita (.) | @ csv, çok kullanışlı! Teşekkürler
flickerfly

3
Örneğiniz, kayıt başına bir satır yerine tüm ekran adlarını ilk satırda ve tüm değerleri ikinci satırda gösterecek.
Brian Gordon

32

Her kaydı CSV’mde bir satır yapmayı tercih ediyorum.

jq '.data | map([.displayName, .rank, .value] | join(", ")) | join("\n")'

2
Ya .value bir sayıysa? Ben hatası "dizesini ve numara eklenemez" alıyorsunuz
Cos

2
Gibi bir şey @Cos .value|tostringyerine .valueYukarıdaki örnek içinde
matheeeny

4
@Cos, parantezin gerekli olduğunu buldum. (.value|tostring)
ciscogambo

Ayrıca, jq -rtırnak işaretleri için kullanın
Clay

30

Sadece bu dosya göz önüne alındığında, gibi bir şey yapabilirsiniz:

<testfile jq -r '.data | map(.displayName), map(.value) | join(", ")'

.Operatör, nesne / karma bir alan seçer. Böylece, .dataiçindeki verileri içeren diziyi döndüren ile başlıyoruz . Daha sonra dizinin üzerinden iki kez eşleştiriyoruz, önce displayName'i seçtikten sonra değeri seçtik, bize sadece bu anahtarların değerlerini içeren iki diziyi verdiler. Her bir dizi için elementleri "," ile iki satır oluşturarak birleştiririz. -rArgüman anlatır jqçıkan dizeleri alıntı için.

Gerçek dosyanız daha uzunsa (örneğin, birden fazla kişi için girdi varsa), muhtemelen biraz daha karmaşık bir şeye ihtiyacınız olacaktır.


Benim için çalışmıyor. İlgili bir konuda stackoverflow.com/questions/32960857/… yanıtı hem çalışıyor, hem de çok iyi açıklanmış durumda!
herve

10

jqKafamı sarmak için zor buldum . İşte biraz Ruby:

ruby -rjson -rcsv -e '
  data = JSON.parse(File.read "file.json")
  data["data"].collect {|item| [item["displayName"], item["value"]]}
              .transpose
              .each {|row| puts row.to_csv}
'
First Name,Last Name,Position,Company Name,Country
VALUE,VALUE,VALUE,VALUE,VALUE

Yakut JSON ayrıştırıcısı, yakın braketten önce sondaki virgül hakkında kabardı.


2

Bunu etiketlediğinizden pythonve jsondosyanın adını varsayarakx.json

import os, json
with open('x.json') as f:
    x  = json.load(f)
    print '{}{}{}'.format(', '.join(y['displayName'] for y in x['data']), os.linesep,
             ', '.join(y['value'] for y in x['data']))
First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE

1

jqBaşka bir dizi elemanı beklemekten şikayetçi olduğum için çalışmasını sağlamak için örnek girişinizdeki son virgüyü kaldırmak zorunda kalmama rağmen :

INPUT | jq -r '[.[][].displayName], [.[][].value]| join(", ")'

...Beni yakaladın...

First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE

Özetle nasıl çalışır:

  1. Boş []dizin alan formunu ve .dotgösterimini kullanarak üçüncü veri nesneleri seviyesine geçtim .
  2. Bir kez yeterince derin, ismiyle istediğim veri alanlarını belirledim .[][].displayName.
  3. İstediğim alanların kendileri gibi ayrı bir dizi nesnesi olarak döndürülerek kendileriyle ilişkilendirildiğinden eminim. [.[][].displayName], [.[][].value]
  4. Ve sonra bu nesneleri join(", ")ayrı ayrı varlıklar olarak birleştirilecek işleve aktarın.

Gerçekte yapmak [.field]sadece başka bir yoldur, map(.field)ancak bu istenen verileri almak için derinlik seviyesini belirlemesi bakımından biraz daha belirgindir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.