基于数组中的元素,使用 jq 从 json 创建 CSV

Creating a CSV from json using jq, based on elements in array

我有以下 json 格式需要转换为 CSV

[{
            "name": "joe",
            "age": 21,
            "skills": [{
                "lang": "spanish",
                "grade": "47",
                "school": {
                    "name": "my school",
                    "url": "example.com/sp-school"
                }
            }, {
                "lang": "english",
                "grade": "87"
            }]

        },

        {
            "name": "sarah",
            "age": 34,
            "skills": [{
                "lang": "french",
                "grade": "47",
                "school": {
                    "name": "my school",
                    "url": "example.com/sp-school"
                }
            }, {
                "lang": "english",
                "grade": "87"
            }]

        }, {
            "name": "jim",
            "age": 26,
            "skills": [{
                "lang": "spanish",
                "grade": "60"

            }, {
                "lang": "english",
                "grade": "66",
                "school": {
                    "name": "eg school",
                    "url": "eg-school.com"

                }
            }]

        }
    ]

转换为 csv

name,age,grade,school,url,file,line_number
joe,21,47,"my school","example.com/sp-school",sample.json,1
jim,26,60,"","",sample.json,3

因此,如果 lang=spanish,则添加顶级字段和 skills 数组中的对象,如果存在,则添加 skills 对象中的 school hash for spanish

我还想添加它来自的文件和行号。

我想使用 jq 来完成这项工作,但无法弄清楚语法,有人帮我吗?

你的数据在input.json,下面的jq程序在tocsv.jq:

.[]
| [.name, .age] +
  (.skills[]
  | select(.lang == "spanish")
  | [.grade, .school.name, .school.url, input_filename, input_line_number] )
| @csv

调用:

jq -r -f tocsv.jq  input.json

产量:

"joe",21,"47","my school","example.com/sp-school","input.json",51
"jim",26,"60",,,"input.json",51

如果要将 number-valued 字符串转换为数字,可以使用 "tonumber" 过滤器。如果您希望 null-valued 字段替换为字符串,请使用例如.school.name // ""

当然,这种方法不会产生非常有用的行号。一种会产生更高粒度的方法是将单个对象流式传输到 jq 中,但这样您会丢失文件名。要恢复文件名,您可以将其作为参数传递。所以你会有一个像这样的管道:

jq -c '.[]' input.json | jq -r --arg file input.json -f tocsv2.jq

其中 tocsv2.jq 类似于上面的 tscsv.jq,但没有初始 .[] |,并且使用 $file 而不是 input_filename

最后,请考虑使用 TSV 格式 (@tsv) 而不是相当混乱的 CSV 格式 (@csv)。