【问题标题】:Structured JSON to CSV with jq使用 jq 将 JSON 结构化为 CSV
【发布时间】:2019-12-09 22:30:08
【问题描述】:

使用jq 我尝试将 JSON 转换为 CSV。这是我的输入 JSON 的样子:

{
  "rows": [
    {
      "a": ["x","y"],
      "b": "some",
      "c": "string"
    },
    {
      "a": ["u","v"],
      "b": "another",
      "c": "string"
    }
  ]
}

想要的输出是这样的:

a   | b       | c
x y | some    | string
u v | another | string

编辑:对于那些抱怨这不是有效的 CSV 的人,这里是符合 RFC 4180 的语法:

a,b,c
x y,some,string
u v,another,string

使用.rows,我成功得到数组:

[{"a":["x","y"],"b":"some","c":"string"},{"a":["u","v"],"b":"another","c":"string"}]

但是.rows | @csv 说:object ({"a":["x","...) is not valid in a csv row。所以,我必须以某种方式加入键“a”中的数组。

使用.rows[] | .a | join(" ") 我得到:

"x y"
"u v"

但是我如何将它返回到我的 JSON 中,然后使用 ... | @csv 来获取我想要的 CSV 数据?

【问题讨论】:

  • 这就是我写“输出就像”的原因。我选择了类似表格的演示文稿,以使我期望的输出结构更加明显,希望对读者来说更容易。但我现在已经在符合 RFC 4180 的语法中添加了预期的 CSV。
  • 扁平化或转置之类的功能可能会有所帮助?

标签: json csv nested export-to-csv jq


【解决方案1】:

根据您的输入,以下 程序:

.rows[]
| map_values(if type == "array" then join(" ") else . end)
| [.[]]
| @csv

产生逗号分隔值输出:

"x y","some","string"
"u v","another","string"

添加标题很简单,所以我将把它留给你。另外,让我指出,由于您指定了 CSV 输出,因此强烈建议使用 @csv,但如果出于某种原因您想避免使用那些有时是多余的引号,您可以使用字符串值来插入引号根据需要标记,然后使用join(",") 而不是@csv

或者,您可能希望将@tsv 编织到您的解决方案中。

警告

上面的解决方案假设 a/b/c 键的顺序始终相同,并且对象没有额外的键等。如果安全是一个问题,那么只需将程序中的 [.[]] 行修改为准确地指定你想要的。

另见:

有关处理标头、确保一致性和通用性的一些想法,请参阅:

jq: Object cannot be csv-formatted, only array

【讨论】:

  • 效果很好,谢谢!但是我很难让它在我的命令行上运行(在 macOS 上)。使用 copy'n'paste 我总是收到“意外的 INVALID_CHARACTER”错误。不仅在我的命令行上,而且在 jq 操场上。自己输入命令解决了这个问题。这是最终对我有用的命令行:jq -r '.rows[] | map_values(if type == "array" then join(" ") else . end) | [.[]] | @csv' < test.json
【解决方案2】:

您要旋转输出有点复杂。
在控制台中打印制表符分隔的输出,但看起来像所需的除了管道

function rotate2CSV(inp) {
  var cols = {}; // will be collected in originalKey:[column values]
  for(var rowNo=0;rowNo<inp.rows.length;rowNo++) {
      var rowData = inp.rows[rowNo];
      for(var colsData in rowData) {
          if(!cols[colsData])  cols[colsData] = [];
          cols[colsData].push(rowData[colsData])
      }
  }
  var res = [[]]; // colls rotated content [header keys], [1st row content], ...
  for(var colsData in cols) {
    var col = res[0].indexOf(colsData);
    if(col < 0) {
      col = res[0].length;
      res[0].push(colsData);
    }
    if(col > -1) {
      for(var row=0;row<cols[colsData].length;row++) {
        if(res.length - 1 <= row) res.push([]);
        var cell = cols[colsData][row];
        if(cell instanceof Array) cell = cell.join(' ');
        res[row+1].push(cell);
      }

    }
  }
  for(var rowNo=0;rowNo<res.length;rowNo++) {
    console.log(res[rowNo].join('\t'))
  }
}
rotate2CSV(
  {
    "rows": [
        {
            "a": ["x", "y"],
            "b": "some",
            "c": "string"
        },
        {
            "a": ["u", "v"],
            "b": "another",
            "c": "string"
        }
    ]
  }
);

【讨论】:

  • 这是JS代码,不是吗?我正在寻找使用命令行工具jq的解决方案。
  • 对不起,想 jQuery,无论如何你可以翻译它,以防它像 JS 一样简单;-) 但是旋转可能很难 - 也许 C# / .net 核心会容易得多。
  • 我应该删除我的 JS 答案吗?
  • @peak
猜你喜欢
  • 2015-06-22
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
相关资源
最近更新 更多