使用 jq 重新格式化 json

使用 jq 重新格式化 json

我有以下 JSON 文件:

{ data : [
  {
   "name" : "name1"
   "date" : [
     {
      "date1" : "aaa",
      "date2" : "bbb"
     },
     {
      "date1" : "ccc",
      "date2" : "ddd"
     },
     {
      "date1" : "eee",
      "date2" : "fff"
     },
     "var" : "ggg"
 },
{
   "name" : "name2"
   "date" : [
     {
      "date1" : "hhh",
      "date2" : "iii"
     },
     {
      "date1" : "jjj",
      "date2" : "kkk"
     },
     "var" : "lll"
  }
 ]
}

我想要以下格式的 CSV 文件:

name, date, var
name1, aaa ccc eee, ggg
name2, hhh jjj, lll

仅使用 jq 可以吗?

答案1

假设您的 JSON 文档格式良好,如您所呈现的文本的以下修改后的变体:

{
  "data": [
    {
      "name": "name1",
      "date": [
        {
          "date1": "aaa",
          "date2": "bbb"
        },
        {
          "date1": "ccc",
          "date2": "ddd"
        },
        {
          "date1": "eee",
          "date2": "fff"
        }
      ],
      "var": "ggg"
    },
    {
      "name": "name2",
      "date": [
        {
          "date1": "hhh",
          "date2": "iii"
        },
        {
          "date1": "jjj",
          "date2": "kkk"
        }
      ],
      "var": "lll"
    }
  ]
}

然后我们可以执行以下操作:

$ jq -r '[ "name", "date", "var" ], (.data[] | [.name, ([.date[].date1] | join(" ")), .var]) | @csv' file
"name","date","var"
"name1","aaa ccc eee","ggg"
"name2","hhh jjj","lll"

这个jq表达式,用更多的空气来显示结构:

[ "name", "date", "var" ],
(
    .data[] |
    [
      .name,
      ( [ .date[].date1 ] | join(" ") ),
      .var
    ]
) |
@csv

这首先将 CSV 标头创建为字符串数组。然后它迭代顶级数组,将和键data的值拉出到数组中。它还挑选出数组中子键的所有值,并将它们与空格作为分隔符连接起来。namevardate1date

data然后,使用 处理CSV 标头数组以及为每个元素构建的数组以进行输出@csv,该数组引用每个字符串并用逗号分隔元素。


另一种变体:

box% jq -r '.data[].date |= ( [.[].date1] | join(" ") ) | [ (.data[0] | keys[]) ], (.data[]| [.[]]) | @csv' file
"date","name","var"
"name1","aaa ccc eee","ggg"
"name2","hhh jjj","lll"

这会对数据进行预处理,以便第一个管道之后的表达式部分获得以下输入:

{
  "data": [
    {
      "name": "name1",
      "date": "aaa ccc eee",
      "var": "ggg"
    },
    {
      "name": "name2",
      "date": "hhh jjj",
      "var": "lll"
    }
  ]
}

第一个管道之后的代码只需提取 CSV 标头的键,然后收集值,而不必担心键的名称。

再次,jq为了说明目的,插入了一点空气的表达式:

.data[].date |= ( [ .[].date1 ] | join(" ") ) |
[ (.data[0] | keys[]) ],
( .data[] | [.[]] ) |
@csv

看起来很时髦,.data[] | [.[]]它创建了一个包含 的每个元素中所有键的值的数组data

如果担心.[]应用于非数组可能会以与keys生成的顺序不同的顺序提取值,那么可以使用

.data[].date |= ( [ .[].date1 ] | join(" ")) |
(.data[0] | keys) as $keys |
$keys,
( .data[]| [ .[$keys[]] ] ) |
@csv

即,将标题键拉出到变量中$keys,使用它来创建 CSV 标头用于从数组中的元素中提取数据data。这些列可能采用随机顺序,但至少标题和其余数据采用相同的随机顺序,并且 CSV 解析器按名称提取列不会有任何问题。

相关内容