JSON Schema规范:if/then/else可否置于对象properties属性内部?
JSON Schema Draft-7:能否将if/then/else放在properties内部?
问题背景
我参考官方文档的条件校验示例,发现所有if/then/else条件都是定义在对象的properties外部的,比如这个标准写法:
{ "type": "object", "properties": { "street_address": { "type": "string" }, "country": { "enum": ["United States of America", "Canada"] } }, "if": { "properties": { "country": { "const": "United States of America" } } }, "then": { "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } }, "else": { "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } } }
我尝试把这些条件关键字放到properties内部,写法如下:
{ "type": "object", "properties": { "street_address": { "type": "string" }, "country": { "enum": ["United States of America", "Canada"] }, "if": { "properties": { "country": { "const": "United States of America" } } }, "then": { "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } }, "else": { "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } } } }
用在线校验工具测试没报错,但不确定是否符合JSON Schema Draft-7规范。我的动机是在大型Schema文件里,希望把依赖其他属性的条件定义在对应属性附近,方便维护,作为编程新手,若问题有误请见谅。
解答
很明确地说:这种写法不符合Draft-7规范,也不会实现你想要的条件校验逻辑,原因如下:
- 关键字作用域问题:
if/then/else是JSON Schema中的实例级关键字,它们的作用域是当前整个对象实例,必须定义在对象的顶级(和type、properties同级),才能起到条件校验的作用。 - 被当作普通属性处理:当你把这些关键字放到
properties内部时,Schema会把它们当成名为"if"、"then"、"else"的普通属性定义,而不是条件逻辑规则。也就是说,你的写法并没有设置任何条件校验,反而允许(甚至要求,如果加了required的话)JSON实例中包含if、then、else这些属性。 - 在线工具不报错的原因:工具只是检查Schema的语法合法性,你的写法语法上是正确的,但逻辑完全偏离了你的预期——它不会根据
country的值来校验postal_code的格式。
替代方案(满足就近维护需求)
如果你想在大型Schema里把相关属性和条件逻辑放在一起,可以用allOf关键字把它们分组,这样既符合规范,又能实现代码就近维护的需求:
{ "type": "object", "allOf": [ // 基础属性定义 { "properties": { "street_address": { "type": "string" }, "country": { "enum": ["United States of America", "Canada"] } } }, // 美国对应的邮编规则 { "if": { "properties": { "country": { "const": "United States of America" } } }, "then": { "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } } }, // 加拿大对应的邮编规则 { "if": { "properties": { "country": { "const": "Canada" } } }, "then": { "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } } } ] }
通过allOf把相关逻辑拆分成独立的块,你可以把每个国家对应的条件规则放在靠近country属性定义的位置,在大型文件里更易读和维护。
内容的提问来源于stack exchange,提问作者Nishit Shetty
相关产品推荐
相关产品推荐

