Python如何解析OpenAPI JSON的$ref引用并替换为实际字典值
OpenAPI 本地$ref引用解析方案
你之前手写的解析逻辑存在两处不符合JSON Pointer(OpenAPI $ref本地引用遵循RFC 6901 JSON Pointer规范)的问题:
- 转义逻辑错误:仅处理了
~1转/,遗漏了~0转~的规则,且转义顺序错误,遇到包含~0的路径会解析失败 - 索引转换逻辑错误:提前把所有数字格式的路径段转成整数,会误将本身为数字字符串的字典Key识别为数组索引,导致取值异常
正确实现代码
import json from typing import Any def resolve_local_ref(ref: str, openapi_obj: dict) -> Any: """ 解析OpenAPI中#开头的本地$ref引用,返回对应实际值 :param ref: $ref字符串,例如#/paths/~1golly~1gee/get/parameters/0 :param openapi_obj: json.loads加载得到的OpenAPI根对象 """ if not ref.startswith("#/"): raise ValueError(f"非本地引用暂不支持解析: {ref}") # 拆分路径段 path_segments = ref.removeprefix("#/").split("/") current_node = openapi_obj for seg in path_segments: # 严格遵循规范顺序转义:先还原~为~0,再还原/为~1,顺序不能调换 seg = seg.replace("~0", "~").replace("~1", "/") # 仅当当前节点是列表类型时,才将路径段转为整数索引 if isinstance(current_node, list): seg = int(seg) current_node = current_node[seg] return current_node
使用示例
# 加载OpenAPI JSON文件 with open("your_openapi.json", "r", encoding="utf-8") as f: p = json.load(f) # 测试解析你提到的两类引用 ref_a = "#/paths/~1golly~1gee/get/parameters/0" ref_b = "#/hey/wtf/~1something~1nothing/yeah" value_a = resolve_local_ref(ref_a, p) value_b = resolve_local_ref(ref_b, p)
批量替换所有$ref的扩展方法
如果需要把整个OpenAPI结构里的所有$ref都替换为实际值,可以加一个递归遍历函数:
def replace_all_refs(node: Any, root_obj: dict) -> Any: if isinstance(node, dict): if "$ref" in node and isinstance(node["$ref"], str) and node["$ref"].startswith("#/"): # 遇到$ref直接返回解析后的值,也可以根据需求合并其他字段 return resolve_local_ref(node["$ref"], root_obj) # 递归处理字典所有值 return {k: replace_all_refs(v, root_obj) for k, v in node.items()} elif isinstance(node, list): # 递归处理列表所有元素 return [replace_all_refs(item, root_obj) for item in node] # 基础类型直接返回 return node # 调用后得到所有$ref被替换完成的OpenAPI对象 resolved_p = replace_all_refs(p, p)
注意:如果你的OpenAPI文件存在跨文件引用,需要额外加文件加载逻辑,把外部文件加载后合并到根对象再做解析即可。
内容的提问来源于stack exchange,提问作者deadcow
相关产品推荐
相关产品推荐

