如何配置递归JSON Schema实现深层对象级联必填字段校验
递归JSON Schema实现深层对象的字段继承校验需求
需求与现有Schema
现有一个支持任意嵌套键的递归JSON Schema,基础结构如下:
{ "type": "object", "properties": { "Age": { "type": "number" }, "Name": { "type": "string" } }, "patternProperties": { ".*": { "$ref": "#" } }, "additionalProperties": false }
当前Schema允许任意键映射到同结构的嵌套对象,但需要新增校验规则:每个最深层对象(即没有子对象的对象),必须自身包含Age和Name字段,或者其任意祖先对象包含这两个字段。
合法示例
{ "level1": { "level2": { "Age": 20, "Name": "test" } } }
{ "level1": { "level2": {}, "Age": 20 }, "Name": "test" }
{ "level1": { "level2": { "Age": 20 } }, "Name": "test" }
{ "level1": { "level2": { "Age": 20 } }, "level3": { "Age": 10 }, "Name": "test" }
非法示例
{ "level1": { "level2": { "Age": 20 } }, "level3": { "Name": "test2" }, "Name": "test" }
非法原因:
level3对象自身没有Age,且其祖先(根对象)未提供Age,不满足校验规则。
实现方案
要实现该逻辑,需利用JSON Schema的$dynamicAnchor和$dynamicRef传递校验上下文——递归校验时需要跟踪祖先是否已提供Age和Name。以下是最终Schema:
{ "$schema": "http://json-schema.org/draft-07/schema#", "$dynamicAnchor": "node", "type": "object", "properties": { "Age": { "type": "number" }, "Name": { "type": "string" } }, "patternProperties": { ".*": { "$dynamicRef": "#node" } }, "additionalProperties": false, "allOf": [ { "if": { "not": { "patternProperties": { ".*": { "type": "object" } }, "minProperties": 1 } }, "then": { "anyOf": [ { "required": ["Age", "Name"] }, { "$dynamicRef": "#node", "required": ["Age"] }, { "$dynamicRef": "#node", "required": ["Name"] } ] } }, { "$dynamicAnchor": "node", "properties": { "Age": { "type": "number" }, "Name": { "type": "string" } } } ] }
方案说明
- 动态锚点传递上下文:
$dynamicAnchor和$dynamicRef配合,让子对象递归校验时能继承父级是否已提供Age/Name的状态,替代传统$ref无法保留上下文的问题。 - 最深层对象判断:通过
not+patternProperties+minProperties组合,判断当前对象是否没有任何子对象(即无匹配.*的键)。 - 最深层校验逻辑:
- 要么自身同时包含
Age和Name; - 要么通过
$dynamicRef回溯祖先,确认祖先已提供这两个字段(动态锚点会保留父级的校验状态)。
- 要么自身同时包含
- 上下文更新:若当前对象有
Age或Name,动态锚点会更新上下文状态,子对象递归时可直接继承这些字段的存在性。
内容的提问来源于stack exchange,提问作者Kenji
相关产品推荐
相关产品推荐

