JSON 架构 oneof 没有要求
JSON Schema oneof without required
在 JSON Schema
草案 7 或草案 8 中,正确的说法是我们想要可选的属性之一而不是两者。我可以用 required
关键字构造,但是你必须包含其中一个必需的属性。这是我能想到的,对吗?
在这个例子中,我试图验证 field_1
是必需的,我们想要其中的一个 field_2
、field_3
或 none。 (查看示例)
{
"$schema": "http://json-schema.org/draft-08/schema#",
"type": "object",
"properties": {
"field_1": {
"type": "string"
},
"field_2": {
"type": "string"
},
"field_3": {
"type": "string"
}
},
"required": [
"field_1"
],
"oneof": [
{
"properties": [
"field_2"
]
},
{
"properties": [
"field_3"
]
}
],
"additionalProperties": false,
"examples": [
{
"field_1": "1",
"field_2": "2"
},
{
"field_1": "1",
"field_3": "3"
},
{
"field_1": "1"
}
]
}
[已编辑 - 请参阅下面的第三个解决方案]
解决方案 1 - 至少一个,但不是两个(详细)
我会添加一个带有嵌套 oneOf
的 allOf
:
{
...
"allOf": [
{
"oneOf": [
{"required": ["field_2"]},
{"required": ["field_3"]}
],
},
{
"not": {
"required": ["field_2", "field_3"]
}
}
],
...
}
这需要两个字段之一存在,但不能同时存在。
解决方案 2 - 至少一个,但不是两个
我认为这可以通过仅使用 oneOf
:
来进一步简化
{
...
"oneOf": [
{"required": ["field_2"]},
{"required": ["field_3"]}
],
...
}
- 如果两者都不存在,那么它们都会失败,
oneOf
也会失败。
- 如果有,则
oneOf
通过。
- 如果两者都存在,那么这两个都会通过,而
oneOf
失败。
是的,这样更好。看看你拥有的东西,我认为这就是你想要做的,所以你 真的 接近了!
解决方案 3 - 最多一个
要在两个字段都不存在时通过,您需要第一个解决方案,但将 allOf
更改为 anyOf
:
{
...
"anyOf": [
{
"oneOf": [
{"required": ["field_2"]},
{"required": ["field_3"]}
],
},
{
"not": {
"required": ["field_2", "field_3"]
}
}
],
...
}
- 如果两者都不存在,则
not
子模式将通过,并且 anyOf
通过。
- 如果存在,则
oneOf
子模式将通过,anyOf
将通过。
- 如果两者都存在,则
- 两个
oneOf
子模式都将通过,因此 oneOf
失败
not
子模式将失败
- 所以
anyOf
失败了
您可以测试这些解决方案here
这里还有几个选项可以添加到@gregdennis 的回答中。
依赖关系
这是 dependencies
关键字的一个很好的用例。这表示,"if there is a "field_2" 不能有 "field_3" 并且,"if there is a "field_3" 不能有 "field_2"。如果 "field_2" 或 "field_3" 都不存在,则不应用任何约束并且模式通过。
"dependencies": {
"field_2": { "not": { "required": ["field_3"] } },
"field_3": { "not": { "required": ["field_2"] } }
}
最大属性
这个有点老套,但它的好处是可以单行。如果需要 "field_1" 并且只允许 "field_2" 或 "field_2" 之一,则此对象中的属性不能超过两个。当心,这个解决方案可能比它的价值更聪明。由于此约束间接起作用,因此将来可能会导致维护困难。
"maxProperties": 2
if/then
这只是 dependencies
选项的更详细版本,但对于阅读架构的人来说可能更具描述性。
"allOf": [
{
"if": { "required": ["field_2"] },
"then": { "not": { "required": ["field_3"] } }
},
{
"if": { "required": ["field_3"] },
"then": { "not": { "required": ["field_2"] } }
}
]
我不得不尝试解决 3 个字段的问题,其中字段 1 也是可选的。这样做揭示了@gregdennis 对 解决方案 3 的回答略多于它需要的,这实现了相同的目标,因为不需要检查所需的单个值,因为两者都不需要。
{
...
"not": {
"required": ["field_2", "field_3"]
}
...
}
要为 3 执行此操作,它看起来像:
{
...
"not": {
"anyOf": [{
"required": ["field_1", "field_2", "field_3"]
},
{
"required": ["field_1", "field_2"]
},
{
"required": ["field_2", "field_3"]
},
{
"required": ["field_1", "field_3"]
}]
}
...
}
随着您添加更多字段,这显然变得不那么有用了。因此,有空间去 N 的更好解决方案如下:
{
...
"anyOf": [
{
"oneOf": [
{"required": ["field_1"]},
{"required": ["field_2"]},
{"required": ["field_3"]}
]
},
{
"not": {
"anyOf": [
{"required": ["field_1"]},
{"required": ["field_2"]},
{"required": ["field_3"]}
]
}
}
]
...
}
你可以玩它here。
在 JSON Schema
草案 7 或草案 8 中,正确的说法是我们想要可选的属性之一而不是两者。我可以用 required
关键字构造,但是你必须包含其中一个必需的属性。这是我能想到的,对吗?
在这个例子中,我试图验证 field_1
是必需的,我们想要其中的一个 field_2
、field_3
或 none。 (查看示例)
{
"$schema": "http://json-schema.org/draft-08/schema#",
"type": "object",
"properties": {
"field_1": {
"type": "string"
},
"field_2": {
"type": "string"
},
"field_3": {
"type": "string"
}
},
"required": [
"field_1"
],
"oneof": [
{
"properties": [
"field_2"
]
},
{
"properties": [
"field_3"
]
}
],
"additionalProperties": false,
"examples": [
{
"field_1": "1",
"field_2": "2"
},
{
"field_1": "1",
"field_3": "3"
},
{
"field_1": "1"
}
]
}
[已编辑 - 请参阅下面的第三个解决方案]
解决方案 1 - 至少一个,但不是两个(详细)
我会添加一个带有嵌套 oneOf
的 allOf
:
{
...
"allOf": [
{
"oneOf": [
{"required": ["field_2"]},
{"required": ["field_3"]}
],
},
{
"not": {
"required": ["field_2", "field_3"]
}
}
],
...
}
这需要两个字段之一存在,但不能同时存在。
解决方案 2 - 至少一个,但不是两个
我认为这可以通过仅使用 oneOf
:
{
...
"oneOf": [
{"required": ["field_2"]},
{"required": ["field_3"]}
],
...
}
- 如果两者都不存在,那么它们都会失败,
oneOf
也会失败。 - 如果有,则
oneOf
通过。 - 如果两者都存在,那么这两个都会通过,而
oneOf
失败。
是的,这样更好。看看你拥有的东西,我认为这就是你想要做的,所以你 真的 接近了!
解决方案 3 - 最多一个
要在两个字段都不存在时通过,您需要第一个解决方案,但将 allOf
更改为 anyOf
:
{
...
"anyOf": [
{
"oneOf": [
{"required": ["field_2"]},
{"required": ["field_3"]}
],
},
{
"not": {
"required": ["field_2", "field_3"]
}
}
],
...
}
- 如果两者都不存在,则
not
子模式将通过,并且anyOf
通过。 - 如果存在,则
oneOf
子模式将通过,anyOf
将通过。 - 如果两者都存在,则
- 两个
oneOf
子模式都将通过,因此oneOf
失败 not
子模式将失败- 所以
anyOf
失败了
- 两个
您可以测试这些解决方案here
这里还有几个选项可以添加到@gregdennis 的回答中。
依赖关系
这是 dependencies
关键字的一个很好的用例。这表示,"if there is a "field_2" 不能有 "field_3" 并且,"if there is a "field_3" 不能有 "field_2"。如果 "field_2" 或 "field_3" 都不存在,则不应用任何约束并且模式通过。
"dependencies": {
"field_2": { "not": { "required": ["field_3"] } },
"field_3": { "not": { "required": ["field_2"] } }
}
最大属性
这个有点老套,但它的好处是可以单行。如果需要 "field_1" 并且只允许 "field_2" 或 "field_2" 之一,则此对象中的属性不能超过两个。当心,这个解决方案可能比它的价值更聪明。由于此约束间接起作用,因此将来可能会导致维护困难。
"maxProperties": 2
if/then
这只是 dependencies
选项的更详细版本,但对于阅读架构的人来说可能更具描述性。
"allOf": [
{
"if": { "required": ["field_2"] },
"then": { "not": { "required": ["field_3"] } }
},
{
"if": { "required": ["field_3"] },
"then": { "not": { "required": ["field_2"] } }
}
]
我不得不尝试解决 3 个字段的问题,其中字段 1 也是可选的。这样做揭示了@gregdennis 对 解决方案 3 的回答略多于它需要的,这实现了相同的目标,因为不需要检查所需的单个值,因为两者都不需要。
{
...
"not": {
"required": ["field_2", "field_3"]
}
...
}
要为 3 执行此操作,它看起来像:
{
...
"not": {
"anyOf": [{
"required": ["field_1", "field_2", "field_3"]
},
{
"required": ["field_1", "field_2"]
},
{
"required": ["field_2", "field_3"]
},
{
"required": ["field_1", "field_3"]
}]
}
...
}
随着您添加更多字段,这显然变得不那么有用了。因此,有空间去 N 的更好解决方案如下:
{
...
"anyOf": [
{
"oneOf": [
{"required": ["field_1"]},
{"required": ["field_2"]},
{"required": ["field_3"]}
]
},
{
"not": {
"anyOf": [
{"required": ["field_1"]},
{"required": ["field_2"]},
{"required": ["field_3"]}
]
}
}
]
...
}
你可以玩它here。