基于引用对象值的JSON Schema条件验证与关联约束咨询
问题背景
给定如下JSON结构:
{ "sources": [ { "id": "foo", "type": "a" }, { "id": "bar", "type": "b" } ], "data": [ { "source-id": "foo", "a-attribute": 10 }, { "source-id": "bar", "b-attribute": 20 } ] }
要求data数组中每个对象的source-id必须匹配sources数组中某一对象的id值,同时需要解决以下技术问题:
- 如何在JSON Schema中表达这一关联关系?
- 如何基于引用的
sources对象的type属性值,对data对象应用条件子模式验证?
进一步需求:当引用的source的type为a时,必须指定a-attribute且不能指定b-attribute;当type为b时,必须指定b-attribute且不能指定a-attribute。该需求能否通过JSON Schema实现,还是需要自定义验证代码?
问题解答
1. 在JSON Schema中表达source-id与sources.id的关联关系
可以使用JSON Schema Draft 2019-09及后续版本支持的$data关键字(部分验证器需手动启用该扩展支持),结合动态引用实现关联校验:
针对data数组中的每个对象,其source-id字段的取值必须存在于sources数组所有对象的id集合中。示例Schema片段如下:
{ "type": "object", "properties": { "sources": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": ["a", "b"] } }, "required": ["id", "type"] } }, "data": { "type": "array", "items": { "type": "object", "properties": { "source-id": { "type": "string", "$data": "/sources/*/id" } }, "required": ["source-id"] } } }, "required": ["sources", "data"] }
$data": "/sources/*/id"表示source-id的取值必须匹配sources数组中任意一个元素的id值,以此实现关联校验。
2. 基于source.type的条件子模式验证及进一步需求实现
该需求完全可以通过JSON Schema实现,无需编写自定义验证代码。核心思路是结合$data关键字动态获取对应source的type值,再使用if/then/else条件关键字进行分支校验:
完整Schema示例如下:
{ "type": "object", "properties": { "sources": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": ["a", "b"] } }, "required": ["id", "type"], "additionalProperties": false }, "uniqueItems": true, "items": { "properties": { "id": { "uniqueItems": true } } } }, "data": { "type": "array", "items": { "type": "object", "properties": { "source-id": { "type": "string", "$data": "/sources/*/id" }, "a-attribute": { "type": "integer" }, "b-attribute": { "type": "integer" } }, "required": ["source-id"], "additionalProperties": false, // 根据关联source的type执行条件校验 "if": { "properties": { "source-id": { "$data": "/sources/[?(@.type == 'a')]/id" } } }, "then": { "required": ["a-attribute"], "not": { "required": ["b-attribute"] } }, "else": { "if": { "properties": { "source-id": { "$data": "/sources/[?(@.type == 'b')]/id" } } }, "then": { "required": ["b-attribute"], "not": { "required": ["a-attribute"] } } } } } }, "required": ["sources", "data"] }
关键逻辑说明:
- 使用
$data": "/sources/[?(@.type == 'a')]/id"筛选出所有type为a的source的id,判断当前source-id是否属于该集合; - 若匹配,则进入
then分支:要求必须包含a-attribute,同时禁止出现b-attribute; - 同理,对
type为b的source执行反向校验; - 通过
additionalProperties: false确保data对象不会出现其他未定义的属性。
注意:部分JSON Schema验证器对JSONPath的支持程度不同,需确认所使用的验证器支持$data关键字及[?()]这类筛选表达式。
内容的提问来源于stack exchange,提问作者Andrea Spadaccini
相关产品推荐
相关产品推荐

