【问题标题】:How can I use jq to create a CSV with multiple headers and detail lines?如何使用 jq 创建具有多个标题和详细信息行的 CSV?
【发布时间】:2020-02-07 23:58:29
【问题描述】:

我想使用 jq 以 CSV 格式输出,但是对于多个标题,然后是多个详细信息。我已经在 Stack Overflow 上看到的解决方案提供了一种插入单个标头的方法,但我没有找到多个标头的任何内容。

为了让您了解我在说什么,这里是一些示例 JSON 输入:

[
  {
  "HDR": [1, "abc"],
  "DTL": [ [101,"Descr A"], [102,"Descr B"] ]
  }, {
  "HDR": [2, "def"],
  "DTL": [ [103,"Descr C"], [104,"Descr D"] ]
  }
]

期望的输出:

HDR|1|abc
DTL|101|Descr A
DTL|102|Descr B
HDR|2|def
DTL|103|Descr C
DTL|104|Descr D

我不知道这是否可能,但到目前为止,我的方法是尝试创建一个过滤器来为我提供以下内容,因为将其转换为我需要的内容将是微不足道的:

["HDR", 1, "abc"]
["DTL", 101, "Descr A"]
["DTL", 102, "Descr B"]
["HDR", 2, "def"]
["DTL", 103, "Descr C"]
["DTL", 104, "Descr D"]

需要明确的是,我知道如何在任意数量的脚本语言中做到这一点,但我真的试图坚持使用单个 jq 过滤器,如果可能的话。

编辑:我应该澄清一下,我不一定需要将“HDR”和“DTL”键复制到 CSV(我可以对它们进行硬编码),所以示例 JSON 可能看起来像这样,如果它使问题更简单。

[
  [
    [1, "abc"],
    [[101,"Descr A"], [102,"Descr B"]]
  ], [
    [2, "def"],
    [[103,"Descr C"], [104,"Descr D"]]
  ]
]

编辑:这个过滤器在技术上用我提供的第二个样本数据(最后一个,只有数组,没有对象)回答了这个问题,但如果除了标题长度之外没有其他原因,我仍然希望得到更好的答案进行硬编码,并将 HDR 放入两组数组中,以便以后可以 flatten() 感觉不对。但我会把它留在这里以供参考。

.[] | flatten(1) | [[["HDR"] + .[0:2]]] as $hdr | .[2:] as $dtl | $dtl | map([["DTL"] + .]) as $dtl | $hdr + $dtl | flatten(1) | .[] | join("|")

【问题讨论】:

    标签: json csv jq


    【解决方案1】:

    这适用于您的原始输入,假设您选择 | 作为分隔符,因为您的任何字段都不能包含 |

    jq -r 'map(["HDR"]+.HDR, ["DTL"] + .DTL[])[] | join("|")' data.json
    
    • map 为每个对象生成多个数组元素。
    • .DTL[] 确保 "DTL" 是每个子列表的前缀
    • []map 的结果展平

    【讨论】:

    • 这比我拥有的要好得多。我喜欢它。谢谢!作为记录,在我正在处理的实际项目中,它是制表符分隔的(并且制表符将被剥离),但我认为管道会更好地说明。
    • 另外,我要感谢您解释过滤器的每个组件的作用。这真的很有帮助。
    • 啊,把join("|")换成@tsv,然后。如果字段本身可能包含选项卡,这将负责引用字段。
    • 其实我弄错了。它将以 0x000F 分隔。读取此输出的应用程序是旧应用程序,根本不会转义字段,因此必须使用不常见的字符作为分隔符。幸运的是 jq 可以轻松做到这一点。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    相关资源
    最近更新 更多