如何使用JSON Schema拆分重构属性,实现多文件$ref引用?
首先你给出的示例中book.json和pencil.json的字段对应关系和原逻辑相反,原逻辑中Book类型关联domain/img_url/url字段、禁止content,Pencil类型关联content、禁止另外三个字段,以下方案会按原逻辑修正。
核心问题说明
- 同一对象下声明多个
$ref会相互覆盖,JSON Schema规定$ref所在对象的其余属性会被忽略,你原来写的在properties下直接放两个$ref的写法是无效的。 - Draft-07及更早版本的
additionalProperties: false只能识别当前同级properties内声明的字段,无法识别跨$ref引入的属性,要保证额外属性校验生效有两种方案可选。
方案1:兼容Draft-07版本,无需升级规范
1. 公共字段文件 common.json 维护通用属性
{ "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": ["Pencil", "Book"] }, "title": { "type": "string" } }, "required": ["id", "type", "title"] }
2. Book类型专属文件 book.json 维护自身规则
{ "type": "object", "properties": { "domain": { "type": "string" }, "img_url": { "type": "string" }, "url": { "type": "string" } }, "if": { "properties": { "type": { "const": "Book" } } }, "then": { "required": ["domain", "img_url", "url"], "not": { "required": ["content"] } } }
3. Pencil类型专属文件 pencil.json 维护自身规则
{ "type": "object", "properties": { "content": { "type": "string" } }, "if": { "properties": { "type": { "const": "Pencil" } } }, "then": { "required": ["content"], "not": { "anyOf": [ { "required": ["domain"] }, { "required": ["img_url"] }, { "required": ["url"] } ] } } }
4. 主入口文件 main.json 整合所有规则
需要把所有允许的字段都在主文件的properties中声明,保证additionalProperties: false生效:
{ "type": "object", "additionalProperties": false, "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": ["Pencil", "Book"] }, "title": { "type": "string" }, "content": { "type": "string" }, "domain": { "type": "string" }, "img_url": { "type": "string" }, "url": { "type": "string" } }, "allOf": [ { "$ref": "./common.json" }, { "$ref": "./book.json" }, { "$ref": "./pencil.json" } ] }
方案2:使用2019-09及以上版本规范,简化结构
如果可以升级JSON Schema版本,用unevaluatedProperties: false替代additionalProperties: false,它可以识别所有跨$ref引入的属性,不需要在主文件重复声明所有字段:
主入口文件简化为:
{ "$schema": "https://json-schema.org/draft/2019-09/schema", "type": "object", "unevaluatedProperties": false, "allOf": [ { "$ref": "./common.json" }, { "$ref": "./book.json" }, { "$ref": "./pencil.json" } ] }
后续修改子类型属性只需要改对应子文件即可,不需要调整主文件配置。
内容的提问来源于stack exchange,提问作者Samuel Da Costa
相关产品推荐
相关产品推荐

