jqを使用して値を抽出し、CSVでフォーマットする


58

以下のJSONファイルがあります。

{
"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"
    },
]
}

この形式のCSVファイルが欲しいです。

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

これを使用するだけで可能jqですか?プログラミングのスキルはありません。


1
以下の回答を提供しましたが、今あなたの質問を詳しく見ており、疑問に思わずにはいられません-6番目のVALUEはどこから来るのでしょうか?
mikeserv 14年


回答:


50

jqには、配列をCSV文字列に変換するためのフィルター@csvがあります。このフィルターは、フィールドに埋め込まれたコンマから始まるCSV形式に関連する複雑さのほとんどを考慮します。(jq 1.5には、タブ区切り値ファイルを生成するための同様のフィルター@tsvがあります。)

もちろん、ヘッダーと値にすべてカンマと二重引用符が含まれていないことが保証されている場合は、@ csvフィルターを使用する必要はありません。そうでなければ、おそらくそれを使用する方が良いでしょう。

たとえば、「会社名」が「Smith、Smith、およびSmith」であり、他の値が以下に示されている場合、「-r」オプションでjqを呼び出すと有効なCSVが生成されます。

$ 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
何かをjqできた| マップ(。)| @csv '、とても便利です!ありがとう
-flickerfly

3
例では、レコードごとに1行ではなく、すべての表示名を最初の行に、すべての値を2行目に配置します。
ブライアンゴードン

33

CSVで各レコードを行にすることを好みます。

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

2
.valueが数値の場合はどうなりますか?「文字列と番号を追加できません」というエラーが表示されます
Cos

2
以下のようなもの@Cos .value|tostringの代わりに、.value上記の例で
matheeeny

4
@Cos、括弧が必要であることがわかりました。(.value|tostring)
ciscogambo

また、jq -r引用符を取り除くために使用します
Clay

30

このファイルだけで、次のようなことができます。

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

.オペレータは、オブジェクト/ハッシュからフィールドを選択します。したがって、.dataデータを含む配列を返すで始まります。次に、配列を2回マッピングします。最初にdisplayNameを選択し、次に値を選択して、それらのキーの値のみを含む2つの配列を取得します。配列ごとに、要素を「、」で結合して2行を形成します。-r引数が伝えjq結果の文字列を引用しないこと。

実際のファイルが長い場合(つまり、複数のユーザーのエントリがある場合)、もう少し複雑なものが必要になる可能性があります。


それは私のために働いていません。関連トピックでは、答えstackoverflow.com/questions/32960857/…は機能しており、非常によく説明されています!
-Herve

10

jq頭を包むのは難しいと感じました。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

ruby JSONパーサーは、閉じ括弧の前の末尾のコンマを無視しました。


2

これにタグを付けpythonjsonファイル名がx.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

jq別の配列要素が必要だと文句を言っていたので、入力例の最後のコンマを削除して機能させる必要がありましたが、これは次のとおりです。

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

...私を見つけました...

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

簡単に言えば:

  1. 空の[]インデックスフィールドのフォームと.dot表記法を使用して、データオブジェクトの第3レベルに移動しました。
  2. 十分に深くなったら、必要なデータフィールドをのような名前で指定しました.[][].displayName
  3. 私の希望するフィールドは、次のような個別の配列オブジェクトとして返すことにより、自己関連付けされていることを保証しました [.[][].displayName], [.[][].value]
  4. そして、それらのオブジェクトをjoin(", ")関数にパイプして、個別のエンティティとして結合します。

実際には、行うこと[.field]は単に別の方法ですがmap(.field)、これは目的のデータを取得するための深さレベルを指定するという点で、もう少し具体的です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.