如何在自引用JSON Schema中排除指定属性与关键字?
问题描述
原始JSON Schema如下:
{"$id": "http://example.com/names.json","type": "object","required": ["id", "name"],"additionalProperties": false,"properties": {"name": {"type": "string"},"id": {"type": "string"},"subscriptions": {"type": "object"}}}
需求是新增draftVersion属性用于存储草稿,要求:
- 草稿可包含主对象的所有核心属性(name、id、subscriptions)
- 草稿不能包含
draftVersion属性,避免深层递归嵌套 - 草稿无需遵循主对象的
required约束(即草稿可以缺少id或name) - 草稿无需遵循主对象的
additionalProperties: false约束(即草稿可以有额外属性)
之前尝试直接引用主Schema并添加not关键字的写法无效:
"draftVersion": {"$ref": "#","not": {"anyOf": [{"required": ["draftVersion"]}]}}
这种写法会将主Schema的required和additionalProperties: false规则带入草稿,导致草稿必须包含id和name、无法添加额外属性,同时递归引用仍允许草稿嵌套draftVersion。
解决方案
正确的做法是避免直接递归引用整个主Schema,而是单独定义草稿的规则,确保其与主对象的约束解耦。以下是符合需求的Schema:
{ "$id": "http://example.com/names.json", "type": "object", "required": ["id", "name"], "additionalProperties": false, "properties": { "name": {"type": "string"}, "id": {"type": "string"}, "subscriptions": {"type": "object"}, "draftVersion": { "type": "object", "properties": { "name": {"type": "string"}, "id": {"type": "string"}, "subscriptions": {"type": "object"} }, "additionalProperties": true, "not": {"required": ["draftVersion"]} } } }
规则说明
- 主对象规则:保留原有的
required: ["id", "name"]和additionalProperties: false,确保主对象的合法性。 - 草稿规则:
- 仅定义主对象的核心属性,未包含
draftVersion,结合not: {"required": ["draftVersion"]}直接禁止草稿中出现draftVersion属性,从根源避免递归嵌套。 - 未设置
required约束,草稿可按需包含核心属性的任意组合(比如仅包含subscriptions)。 - 设置
additionalProperties: true,允许草稿包含核心属性之外的其他属性。
- 仅定义主对象的核心属性,未包含
如果使用JSON Schema 2020-12及以上版本,还可以用$defs抽离核心属性提升复用性:
{ "$id": "http://example.com/names.json", "$defs": { "coreProperties": { "properties": { "name": {"type": "string"}, "id": {"type": "string"}, "subscriptions": {"type": "object"} } } }, "type": "object", "required": ["id", "name"], "additionalProperties": false, "properties": { "name": {"$ref": "#/$defs/coreProperties/properties/name"}, "id": {"$ref": "#/$defs/coreProperties/properties/id"}, "subscriptions": {"$ref": "#/$defs/coreProperties/properties/subscriptions"}, "draftVersion": { "type": "object", "$ref": "#/$defs/coreProperties", "additionalProperties": true, "not": {"required": ["draftVersion"]} } } }
修改后,你提供的合法示例:
{"name": "abc","id": "123","draftVersion": {"subscriptions": {"id": 123}}}
会被Schema验证通过,而包含嵌套draftVersion的对象则会被拒绝。
内容的提问来源于stack exchange,提问作者Jarede
相关产品推荐
相关产品推荐

