使用jq提取CSV格式的值和格式


57

我有以下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个应该从哪里来?
mikeserv 2014年


Answers:


49

jq有一个过滤器@csv,用于将数组转换为CSV字符串。此过滤器考虑了与CSV格式相关的大多数复杂性,从字段中嵌入的逗号开始。(jq 1.5具有类似的过滤器@tsv,用于生成制表符分隔值的文件。)

当然,如果可以保证标头和值都不含逗号和双引号,则可能无需使用@csv过滤器。否则,使用它可能会更好。

例如,如果“公司名称”为“史密斯,史密斯和史密斯”,并且其他值如下所示,则使用“ -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 somestuff | map(。)| @csv',非常方便!谢谢
flickerfly

3
您的示例将把所有显示名称放在第一行,将所有值放在第二行,而不是每条记录有一行。
布赖恩·戈登

32

我更喜欢使每条记录在CSV中排成一行。

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

2
如果.value是数字怎么办?我收到错误“无法添加字符串和数字”的信息
Cos

2
@Cos像.value|tostring,而不是.value在上面的例子中
matheeeny

4
@Cos,我发现需要括号。(.value|tostring)
ciscogambo16年

此外,使用jq -r剥离引号
克莱

30

仅给出此文件,您可以执行以下操作:

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

.操作者从对象/散列选择字段。因此,我们从开始.data,返回包含数据的数组。然后,我们在数组上进行两次映射,首先选择displayName,然后选择值,为我们提供两个仅包含这些键的值的数组。对于每个数组,我们使用“,”将元素连接起来,形成两行。该-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

由于您标记了这个python并且假设json文件名是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符号遍历了数据对象的第三级。
  2. 足够深后,我通过名称指定了我想要的数据字段.[][].displayName
  3. 通过将它们作为单独的数组对象返回,我确保了所需的字段是自相关的 [.[][].displayName], [.[][].value]
  4. 然后将这些对象通过管道传递join(", ")给要作为单独实体进行连接的函数。

实际上,这样做[.field]只是另一种方式,map(.field)但这更加具体,因为它指定了用于检索所需数据的深度级别。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.