跳到主要内容

Schema 组合

JSON Schema 包含一些用于将模式组合在一起的关键字。请注意,这并不一定意味着组合来自多个文件或 JSON 树的模式,尽管这些工具有助于实现这一点,并且在构建复杂模式中进行了描述。组合模式可能就像允许同时根据多个标准验证一个值一样简单。

这些关键字对应于众所周知的布尔代数概念,如 AND、OR、XOR 和 NOT。您通常可以使用这些关键字来表达无法用标准 JSON Schema 关键字表达的复杂约束。

用于组合模式的关键字是:

  • allOf : (AND) 必须对所有子模式有效
  • anyOf : (OR) 必须对任何子模式有效
  • oneOf : (XOR) 必须对恰好一个子模式有效

所有这些关键字都必须设置为一个数组,其中每个项目都是一个模式。

此外,还有:

  • 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

模式组合的属性

子模式独立

注意:allOfanyOfoneOf数组中列出的模式彼此一无所知。例如,假设您在一个$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"
}

不幸的是,现在模式将拒绝一切。这是因为additionalPropertiesallOf数组内的子模式中声明的属性一无所知

对许多人来说,这是 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 }
]
}