You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python3中实现JSON树剪枝及节点增删提取操作

Python3 实现JSON树按数字索引路径剪枝

核心规则说明

路径索引仅统计值为dict(JSON对象)类型的节点,普通值类型(字符串、数字、布尔、null)不占用索引位:

  • 根节点固定标记为0
  • 每一层级的dict类型子节点按出现顺序从0开始编号,路径按层级追加索引,比如根节点下第一个dict子节点路径为0.0,第二个为0.1
  • 所有操作针对dict类型节点,插入/提取/删除的单位为完整的键值对(包含key和对应的dict值)

实现代码

from copy import deepcopy

def parse_path(path_str: str) -> list[int]:
    """解析路径字符串为整数索引列表"""
    parts = list(map(int, path_str.split('.')))
    if not parts or parts[0] != 0:
        raise ValueError("路径必须以0开头,代表根节点")
    return parts

def _get_parent_and_target(root: dict, path_parts: list[int]):
    """定位到目标路径的父节点,返回(父节点, 目标索引, 目标节点对应的key)"""
    current = root
    # 遍历到父节点(路径倒数第二位)
    for idx in path_parts[1:-1]:
        # 收集当前节点下所有dict类型子节点,按顺序排列
        child_dicts = [(k, v) for k, v in current.items() if isinstance(v, dict)]
        if idx < 0 or idx >= len(child_dicts):
            raise IndexError(f"路径索引{idx}超出当前层级子节点范围,当前层级共有{len(child_dicts)}个对象子节点")
        _, current = child_dicts[idx]
    # 拿到目标位索引
    target_idx = path_parts[-1]
    child_dicts = [(k, v) for k, v in current.items() if isinstance(v, dict)]
    if target_idx < 0 or target_idx > len(child_dicts):
        raise IndexError(f"目标索引{target_idx}非法,当前层级可插入/操作的索引范围为0~{len(child_dicts)}")
    target_key = child_dicts[target_idx][0] if target_idx < len(child_dicts) else None
    return current, target_idx, target_key

def upsert_node(root: dict, path_str: str, node_kv: dict) -> None:
    """
    在指定路径插入/替换节点
    :param root: 原始JSON根节点(dict类型)
    :param path_str: 数字索引路径,如"0.1.2"
    :param node_kv: 待插入的单键值对dict,如{"field2x": {"field3x": "val3x"}}
    """
    if len(node_kv) != 1:
        raise ValueError("待插入内容必须是单键值对,对应一个路径节点")
    path_parts = parse_path(path_str)
    parent, target_idx, old_key = _get_parent_and_target(root, path_parts)
    insert_key, insert_val = next(iter(node_kv.items()))
    if not isinstance(insert_val, dict):
        raise ValueError("待插入节点的值必须是dict类型")
    # 如果是替换已有节点,先删除旧键
    if old_key is not None:
        del parent[old_key]
    # 按位置插入新键:重新构造dict保证顺序
    items = list(parent.items())
    # 计算插入位置:找到第target_idx个dict子节点的位置,插在它前面
    insert_pos = 0
    dict_count = 0
    for i, (k, v) in enumerate(items):
        if isinstance(v, dict):
            if dict_count == target_idx:
                insert_pos = i
                break
            dict_count += 1
    else:
        # 插在末尾
        insert_pos = len(items)
    items.insert(insert_pos, (insert_key, insert_val))
    # 替换父节点内容
    parent.clear()
    parent.update(items)

def delete_node(root: dict, path_str: str) -> dict:
    """
    删除指定路径的节点,返回被删除的键值对
    """
    path_parts = parse_path(path_str)
    if len(path_parts) == 1:
        raise ValueError("不能删除根节点")
    parent, _, target_key = _get_parent_and_target(root, path_parts)
    deleted_val = parent.pop(target_key)
    return {target_key: deleted_val}

def extract_node(root: dict, path_str: str) -> dict:
    """
    提取指定路径的子树(提取后原树会移除该节点),返回被提取的键值对
    """
    return delete_node(root, path_str)

使用示例

对应需求中的操作流程:

import json

# 初始结构
initial_json = {
    "field1": "value1",
    "field2": {
        "field3": "val3",
        "field4": "val4"
    }
}
root = deepcopy(initial_json)
print("初始结构:", json.dumps(root, ensure_ascii=False, indent=2))

# 插入0.1节点
upsert_node(root, "0.1", {
    "field2x": {
        "field3x": "val3x",
        "field4x": "val4x"
    }
})
print("插入0.1后:", json.dumps(root, ensure_ascii=False, indent=2))

# 在0.1下插入0.1.0节点
upsert_node(root, "0.1.0", {
    "field2xx": {
        "field3xx": "val3xx",
        "field4xx": "val4xx"
    }
})
print("插入0.1.0后:", json.dumps(root, ensure_ascii=False, indent=2))

# 提取0.1节点
extracted = extract_node(root, "0.1")
print("提取的0.1节点内容:", json.dumps(extracted, ensure_ascii=False, indent=2))
print("提取后剩余结构:", json.dumps(root, ensure_ascii=False, indent=2))

实现说明

  • 依赖Python3.7+版本,利用原生dict的插入顺序保证索引顺序和JSON结构顺序一致,不需要额外的线性化、树节点封装逻辑,代码可维护性高
  • 所有操作直接修改传入的根节点对象,不需要指针模拟,适配Python语言特性
  • 内置路径校验逻辑,非法路径会抛出明确的异常信息
  • 数组类型的兼容可以按需扩展_get_parent_and_target中的子节点收集逻辑,当前实现完全匹配医疗文件结构化场景下全对象嵌套的使用需求

内容的提问来源于stack exchange,提问作者Ursa Major

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:12:31