如何用JQ将多层嵌套树形JSON转换为含路径的CSV?
问题描述
我有如下树形结构的PDF书签:
Content Author 1 Piece 1 Piece 2 Author 2 Piece 3 Piece 4 Movement 1 Movement 2 Movement 3 Piece 5
通过qpdf可将其格式化为如下JSON:
{ "version": 2, "parameters": { "decodelevel": "generalized" }, "outlines": [ { "dest": [ "4 0 R", "/Fit" ], "destpageposfrom1": 1, "kids": [ { "dest": [ "10 0 R", "/Fit" ], "destpageposfrom1": 2, "kids": [ { "dest": [ "10 0 R", "/Fit" ], "destpageposfrom1": 2, "kids": [], "object": "177 0 R", "open": true, "title": "Piece 1" }, { "dest": [ "15 0 R", "/Fit" ], "destpageposfrom1": 3, "kids": [], "object": "178 0 R", "open": true, "title": "Piece 2" } ], "object": "176 0 R", "open": true, "title": "Author 1" }, { "dest": [ "38 0 R", "/Fit" ], "destpageposfrom1": 4, "kids": [ { "dest": [ "38 0 R", "/Fit" ], "destpageposfrom1": 4, "kids": [], "object": "180 0 R", "open": true, "title": "Piece 3" }, { "dest": [ "45 0 R", "/Fit" ], "destpageposfrom1": 5, "kids": [ { "dest": [ "45 0 R", "/Fit" ], "destpageposfrom1": 5, "kids": [], "object": "182 0 R", "open": true, "title": "Movement 1" }, { "dest": [ "53 0 R", "/Fit" ], "destpageposfrom1": 6, "kids": [], "object": "183 0 R", "open": true, "title": "Movement 2" }, { "dest": [ "58 0 R", "/Fit" ], "destpageposfrom1": 7, "kids": [], "object": "184 0 R", "open": true, "title": "Movement 3" } ], "object": "181 0 R", "open": true, "title": "Piece 4" }, { "dest": [ "79 0 R", "/Fit" ], "destpageposfrom1": 8, "kids": [], "object": "185 0 R", "open": true, "title": "Piece 5" } ], "object": "179 0 R", "open": true, "title": "Author 2" } ], "object": "175 0 R", "open": true, "title": "Contents" } ] }
需要生成CSV文件,保留每个分支的最后一个title,同时记录到达该节点的完整路径及其目标页码,格式如下:
Piece 1;Author 1;Content;2 Piece 2;Author 1;Content;3 Piece 3;Author 2;Content;4 Movement 1;Piece 4;Author 2;Content;5 Movement 2;Piece 4;Author 2;Content;6 Movement 3;Piece 4;Author 2;Content;7 Piece 5;Author 2;Content;8
JQ解决方案
可以使用以下JQ命令处理上述JSON,直接生成目标格式的CSV:
jq -r 'def walk_path($path): .title as $title | ($path + [$title]) as $new_path | if .kids | length == 0 then ($new_path | reverse | join(";")) + ";" + (.destpageposfrom1 | tostring) else .kids[] | walk_path($new_path) end; .outlines[] | walk_path([])' input.json
逻辑说明:
- 自定义递归函数
walk_path($path):- 把当前节点的
title加入到传入的路径数组中,生成新路径$new_path - 若当前节点没有子节点(
.kids数组长度为0),则将路径反转后用;拼接,再追加页码,输出一行结果 - 若当前节点有子节点,则递归处理每个子节点,传递更新后的路径数组
- 把当前节点的
- 主执行逻辑:从
outlines数组的根节点开始调用递归函数,初始路径为空数组。
执行命令后,输出结果将完全匹配期望的CSV格式。
内容的提问来源于stack exchange,提问作者user30622754
相关产品推荐
相关产品推荐

