Schema 组合
JSON Schema 包含一些用于将模式组合在一起的关键字。请注意,这并不一定意味着组合来自多个文件或 JSON 树的模式,尽管这些工具有助于实现这一点,并且在构建复杂模式中进行了描述。组合模式可能就像允许同时根据多个标准验证一个值一样简单。
这些关键字对应于众所周知的布尔代数概念,如 AND、OR、XOR 和 NOT。您通常可以使用这些关键字来表达无法用标准 JSON Schema 关键字表达的复杂约束。
用于组合模式的关键字是:
所有这些关键字都必须设置为一个数组,其中每个项目都是一个模式。
此外,还有:
- not : (NOT)不能对给定的模式有效
allOf
要验证allOf
,给定的数据必须针对给定的所有子模式有效。
{
"allOf": [
{ "type": "string" },
{ "maxLength": 5 }
]
}
"short" // OK
"too long" // not OK
注意:在面向对象继承的意义上, allOf不能用于“扩展”模式以向其添加更多细节。实例必须对 allOf
包含每一个模式都有效. 有关更多信息,请参阅有关子模式独立性的部分。
anyOf
要验证anyOf
,数据必须满足任意一个或多个给定子模式。
{
"anyOf": [
{ "type": "string", "maxLength": 5 },
{ "type": "number", "minimum": 0 }
]
}
"short" // OK
"too long" // not OK
12 // OK
-5 // not OK
oneOf
要验证oneOf
,数据必须满足且只满足一个给定的子模式。
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
10 // OK
9 // OK
2 // not OK,不是 5 或 3 的倍数。
15 // not OK,同时符合两个子模式被拒绝。
not
要验证not
,数据不能满足给定的子模式。
例如,以下模式针对不是字符串的任何内容进行验证:
{ "not": { "type": "string"} }
42 // OK
{ "key": "value" } // OK
"I am a string" // not OK
模式组合的属性
子模式独立
注意:allOf、anyOf 或oneOf数组中列出的模式彼此一无所知。例如,假设您在一个$defs
部分中有一个地址的架构,并且想要“扩展”它以包含地址类型:
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"allOf": [
{ "$ref": "#/$defs/address" },
{
"properties": {
"type": { "enum": [ "residential", "business" ] }
}
}
]
}
{// OK
"street_address": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC",
"type": "business"
}
这是可行的,但是如果我们想限制模式以便不允许附加属性怎么办?可以尝试添加"additionalProperties": false
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"allOf": [
{ "$ref": "#/$defs/address" },
{
"properties": {
"type": { "enum": [ "residential", "business" ] }
}
}
],
"additionalProperties": false
}
// not OK
{
"street_address": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC",
"type": "business"
}
不幸的是,现在模式将拒绝一切。这是因为additionalProperties
对allOf数组内的子模式中声明的属性一无所知。
对许多人来说,这是 JSON 模式中组合操作的最大惊喜之一:它的行为不像面向对象语言中的继承。在 JSON 模式规范的下一版本中,有一些建议可以解决这个问题。
不合逻辑的模式
请注意,使用这些关键字创建逻辑上不可能的模式非常容易。以下示例创建了一个不会针对任何内容进行验证的架构(因为某些内容可能不会同时是字符串和数字):
{
"allOf": [
{ "type": "string" },
{ "type": "number" }
]
}
"No way" // not OK
-1 // not OK
分解模式
请注意,可以“分解”子模式的公共部分。以下两个模式是等效的。
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
{
"type": "number",
"oneOf": [
{ "multipleOf": 5 },
{ "multipleOf": 3 }
]
}