JSON Schema外部嵌套引用路径错误致文件找不到的解决方法
问题场景
我需要创建Schema A(路径为$(pwd)/my-foo.com/schemas/parent-nested.schema.json)来引用Schema B(路径为$(pwd)/my-foo.com/schemas/nested.schema.json),其中Schema B包含指向自身$defs的$ref。单独验证Schema B时一切正常,但验证Schema A时,jsonschema会抛出文件找不到的错误,错误路径里出现了my-foo.com/schemas重复的情况;如果移除Schema B中对自身$defs的引用,验证Schema A就能正常运行。请问该如何指定$ref路径或base-uri来解决这个问题?
问题根源
当Schema A引用Schema B后,Schema B内部的相对路径$ref会默认以Schema A的文件路径为基准进行解析,而非Schema B自身的路径,导致路径拼接错误,出现重复的目录片段。
解决方案
1. Schema B内部使用片段式自引用
在Schema B中,引用自身$defs时,直接使用#/$defs/[定义名]的片段引用格式,这种方式会直接在当前Schema(即Schema B)内部查找目标定义,不依赖外部基准路径,无论被哪个Schema引用都能正确解析。
示例代码:
// nested.schema.json { "$schema": "http://json-schema.org/draft-07/schema#", "$defs": { "nestedType": { "type": "object", "properties": { "name": { "type": "string" } } } }, "type": "object", "properties": { "child": { "$ref": "#/$defs/nestedType" } } }
2. 为Schema B设置$id指定基准URI
在Schema B的根节点添加$id字段,明确指定自身的绝对URI(可以是本地文件路径或自定义命名空间URI),这样内部的$ref会以这个$id为基准解析,不受引用它的Schema影响。
方式一:使用本地绝对文件路径
// nested.schema.json { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "file:///完整路径/my-foo.com/schemas/nested.schema.json", // 替换为实际绝对路径 "$defs": { "nestedType": { ... } }, "properties": { "child": { "$ref": "#/$defs/nestedType" } } }
方式二:使用自定义命名空间URI
如果使用自定义命名空间(如https://my-foo.com/schemas/nested),需要在验证时将URI映射到实际文件路径。以Python的jsonschema库为例:
from jsonschema import RefResolver, validate import json # 加载两个Schema文件 with open("my-foo.com/schemas/parent-nested.schema.json") as f: schema_a = json.load(f) with open("my-foo.com/schemas/nested.schema.json") as f: schema_b = json.load(f) # 注册URI与Schema的映射 resolver = RefResolver( base_uri="https://my-foo.com/schemas/", referrer=schema_a, store={ "https://my-foo.com/schemas/nested": schema_b } ) # 执行验证 validate(instance={"parent": {"child": {"name": "test"}}}, schema=schema_a, resolver=resolver)
3. 确保Schema A引用Schema B的路径正确
因为两个Schema文件在同一目录下,Schema A引用Schema B时直接使用文件名即可,无需额外路径:
// parent-nested.schema.json { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "parent": { "$ref": "nested.schema.json" } } }
结合第一种解决方案(Schema B内部用片段式自引用),即可彻底解决路径重复的问题。
内容的提问来源于stack exchange,提问作者xgord

