如何使用jq将任意嵌套JSON转换为可还原的CSV格式
如何使用jq将包含嵌套结构的任意JSON对象数组转换为CSV格式
目前已有的同类解决方案大多需要提前指定输入输出的特定字段,我需要满足以下要求的通用方案:
- 输出包含表头行
- 适配任意JSON输入,包括嵌套数组和对象
- 支持部分记录缺失其他记录存在的键对应值的场景
- 不硬编码任何字段名称
- 支持将生成的CSV还原为原始嵌套JSON结构
- 使用键路径作为表头名称(点表示法)
点表示法说明
很多使用JSON的产品、工具库都采用这类语法:通过点拼接键片段来访问嵌套属性/子字段。比如键路径a.b.0.c就可以指代如下JSON中的123值:
{ "a": { "b": [ { "c": 123 } ] } }
注意事项:该方法默认属性名中不包含点字符,如果属性名本身带点需要额外设计转义逻辑,本实现为了简化默认按属性名无点的场景处理。
输入示例JSON数组
[ { "a": { "b": [ { "c": 123 } ] } }, { "a": { "b": [ { "c": "foo \" bar", "d": "qux" } ] } }, { "a": { "b": [ { "d": 456 } ] } } ]
预期输出CSV
表头会包含所有出现过的字段,每一行对应输入数组中的一个对象,示例输出如下:
"a.b.0.c","a.b.0.d" 123, "foo "" bar","qux" ,456
可用jq命令
直接执行即可得到符合要求的输出:
cat example.json | jq -r ' # 辅助函数:将单个嵌套对象展开为「点路径: 叶子值」的平面对象 def path_values: reduce (paths(scalars) as $p | {path: $p | join("."), value: getpath($p)}) as $item ({}; .[$item.path] = $item.value); # 第一步:遍历所有输入对象,收集所有出现过的点路径去重作为CSV表头 ( map(path_values | keys) | add | unique ) as $headers # 输出表头行 | ( $headers | map(@csv) | join(",") ) # 逐行输出每个对象的对应值 , ( .[] | path_values as $pv | $headers | map( $pv[.] ) | map( if type == "string" then . else tostring end ) | @csv ) '
实现说明
- 先通过
paths(scalars)获取每个JSON对象所有叶子节点的路径,拼接为点分隔的字符串,把嵌套结构转为平面对象 - 提前遍历所有输入对象,收集全量出现过的点路径去重作为表头,保证不会遗漏后续对象独有的字段
- 逐行处理每个输入对象,按照表头顺序填充对应值,不存在的字段自动留空
- 原生调用jq的
@csv格式化工具,自动处理CSV转义规则,比如双引号转义、特殊字符自动包裹等
内容的提问来源于stack exchange,提问作者opyh
相关产品推荐
相关产品推荐

