能否使用jq将路径式JSON转换为带ID与路径的嵌套树形结构?
使用jq将扁平JSON转换为带ID和路径的嵌套树形结构
原始输入数据
首先修正原始JSON的格式问题(Key/Value需加双引号):
[ {"Key": "fruits/red/apple", "Value": "Red apples"}, {"Key":"fruits/green/lime", "Value": "Green Limes"}, {"Key": "fruits/blue/berries/blueberry", "Value": "Blue Berries"}, {"Key": "vegetables/red/tomato", "Value": "Red Tomatoes"}, {"Key": "vegetables/green/cucumber", "Value": "Green Cucumbers"} ]
目标嵌套树形结构
{ "fruits": { "id": 1, "name": "fruits", "children": [ { "id": 2, "name": "red", "path": "1.2", "children": [ { "id": 3, "name": "apple", "path": "1.2.3", "description": "Red apples" } ] }, { "id": 4, "name": "green", "path": "1.4", "children": [ {"id": 5, "name": "lime", "path": "1.4.5", "description": "Green Limes"} ] }, { "id": 6, "name": "blue", "path": "1.6", "children": [ {"id": 7, "name": "berries", "path": "1.6.7", "children": [{ "id": 8, "name": "blueberry", "path": "1.6.7.8", "description": "Blue Berries" }] } ] } ] }, "vegetables": { "id": 9, "name": "vegetables", "children": [ { "id": 10, "name": "red", "path": "9.10", "children": [ {"id": 11, "name": "tomato", "path": "9.10.11", "description": "Red Tomatoes"} ] }, { "id": 12, "name": "green", "path": "9.12", "children": [ {"id": 13, "name": "cucumber", "path": "9.12.13", "description": "Green Cucumbers"} ] } ] } }
jq实现代码
# 初始化全局可变计数器 [0] as $counter # 定义递归构建节点的核心函数 | def build_node(path_components, parent_path, description): $counter[0] += 1 | . as $id | { "id": $id, "name": path_components[0], "path": (parent_path + ($id | tostring)) | if parent_path == "" then . else .[1:] end } | if path_components | length > 1 then . + { "children": [build_node(path_components[1:], parent_path + "." + ($id | tostring), description)] } else . + { "description": description } end; # 遍历输入项,逐步构建嵌套结构 reduce .[] as $item ({}; ($item.Key | split("/")) as $parts | $item.Value as $desc | # 先确保所有父节点存在 reduce $parts[0:-1] as $part (.; .[$part] //= build_node([$part], "", null) ) | # 构建完整路径的节点并插入结果 setpath($parts; build_node($parts; "", $desc)) )
代码逻辑说明
- 全局计数器:用数组
[0]实现可变计数器,每次创建节点时自增,保证ID全局唯一且连续。 - 递归节点构建:
build_node函数接收路径片段、父路径、描述三个参数,每次调用生成唯一ID。- 根据路径片段长度判断是否为叶子节点:非叶子节点递归生成子节点,叶子节点添加描述字段。
- 路径拼接:根节点路径直接用ID,子节点路径为
父路径.ID格式,确保层级关系清晰。
- reduce遍历处理:
- 拆分每个输入项的Key为路径片段,先构建所有中间父节点(比如
fruits/red/apple先确保fruits和red节点存在)。 - 最后用
setpath将完整路径的节点插入结果结构,自动合并已存在的父节点。
- 拆分每个输入项的Key为路径片段,先构建所有中间父节点(比如
注意事项
- 原始输入必须是合法JSON,所有键名和字符串值需用双引号包裹。
- 路径字段处理为字符串类型(JSON不支持多级数字格式的路径),可根据需求调整格式。
- 计数器从1开始自增,所有节点ID连续不重复。
内容的提问来源于stack exchange,提问作者Siva
相关产品推荐
相关产品推荐

