如何将此 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
我想将此 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