如何将此 json 展平为 tsv?

How to flatten this json as a tsv?

我想将此 JSON 扁平化为 tsv 文件。

https://www.vi4io.org/assets/io500/2019-06/data.json

问题是每个条目({}的第一层)都有很多fields/subfields。我不想指定那么多字段名称。并且不能保证 fields/subfields 在所有条目中都相同。因此,我希望结果列包含所有 fileds/subfields 的并集。列名称的排序应尽可能接近原始 json 文件。 (例如,同一字段中的那些子字段应一起列在 tsv 中)。

将此 json 文件转换为 tsv 的最佳方法是什么?谢谢

如果 jq 不是强制性的,您可以使用 Miller https://github.com/johnkerl/miller

命令是

curl "https://www.vi4io.org/assets/io500/2019-06/data.json" | mlr --j2t unsparsify >output.tsv

如果您想将输出字段名称从 information:data 之类的名称重命名为 information_data,您可以这样使用 rename 动词:

curl "https://www.vi4io.org/assets/io500/2019-06/data.json" | mlr --j2t unsparsify then rename -r '(.+):(.+),_' >output.tsv

这是一个 jq 解决方案,它适用于 JSON object 的任何数组,没有限制,但请参阅下面的 "Caveats"。

json2tsv.jq

# Given an array of JSON objects, 
# produce "TSV" rows, with a header row.
# Handle terminal arrays specially if they are flat.


# emit a stream
def json2headers:
  def isscalar: type | . != "array" and . != "object";
  def isflat: all(.[]; isscalar);
  paths as $p
  | getpath($p)
  | if type == "array" and isflat then $p
     elif isscalar and (($p[-1]|type) == "string") then $p
     else empty end ;

def json2array($header):
   [$header[] as $p | (try getpath($p) catch null)] ;

def json2tsv:
  ( [.[] | json2headers] | unique) as $h
  | ([$h[]|join("_") ],
     (.[]
      | json2array($h)
      | map( if type == "array" then map(tostring)|join("|") else tostring end)))
  | @tsv ;

用法

jq -r -L. 'include "json2tsv"; json2tsv' input.json

输出

输入样本很大,所以这里我只展示header,并单独举例

Header

find_easy   information_URL information_client_kernel_version   information_client_nodes    information_client_operating_system information_client_operating_system_version information_client_procs_per_node   information_comment information_data    information_ds_network  information_ds_nodes    information_ds_operating_system_version information_ds_software_version information_ds_storage_devices  information_ds_storage_interface    information_ds_storage_type information_ds_volatile_memory_capacity information_embargo_end_date    information_filesystem_name information_filesystem_type information_filesystem_version  information_id  information_institution information_list    information_md_network  information_md_nodes    information_md_operating_system_version information_md_software_version information_md_storage_devices  information_md_storage_interface    information_md_storage_type information_md_volatile_memory_capacity information_note    information_storage_install_date    information_storage_refresh_date    information_storage_vendor  information_submission_date information_submitter   information_system  information_vendorURL   information_whatever    io500_md    io500_score ior_easy_read   ior_easy_write  ior_hard_read   ior_hard_write  mdtest_easy_delete  mdtest_easy_stat    mdtest_easy_write   mdtest_hard_delete  mdtest_hard_read    mdtest_hard_stat    mdtest_hard_write

简短示例

input.json

[ {a: [1,2], b: {c:3, d: [{e:4},{e:5, f:6}]}},
  {b: {d: [{e:4},{f:6, e:5}], c:3}, a:[101,102] } ]
输出
a   b_c b_d_0_e b_d_1_e b_d_1_f
1|2 3   4   5   6
101|102 3   4   5   6

input.json(德米特里的变体)

[ {a:[1,2],b:{c:3,d:[{e:4},{e:5,f:6}]}},
  {b:{d:[{e:4},{f:6}],c:3},a:[101,102]} ]
输出
a   b_c b_d_0_e b_d_1_e b_d_1_f
1|2 3   4   5   6
101|102 3   4   null    6

Objects 结构不同

[ {a: [1,2], b: {c: 3}},
  {a: [4,5], b: {c: {d: 6 } } }
输出
a   b_c b_c_d
1|2 3   null
4|5 {"d":6} 6

注意事项

  • 对于top-level数组中的每个object,计算所有标量和scalar-valued数组的路径;如果任何此类路径在另一个 top-level object 中无效,则输出中的相应值将是 null,如上一个示例所示。

  • 平面数组转换为 pipe-separated 值,因此如果输入包含数组,例如 ["1|2", ["3|4"],它将是与字符串值“1|2|3|4”等无法区分。如果这是一个问题,用作数组项分隔符值的字符当然可以更改。

  • header 名称可能会发生类似的冲突。

  • jq 的 @tsv""null 生成一个空字符串,因此如果区分两者很重要,您不妨考虑使用在调用 @tsv.

  • 之前适当的 map