jsonschema - oneOf 关键字行为异常
jsonschema - oneOf keyword behaves unexpectedly
我正在尝试使用 jsonschema 3.0.1
验证 Python 中的 json
有效载荷,大致看起来像这样(简化了麻烦的部分):
{
"request": {
"topic": {
"param1": "bleep beep topic",
"param2": "bloop boop topic"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
一个有效的请求应该有两个字段:一个topic
和匹配的message
.
它们中的每一个都可以仅包含 param1
或 两者 param1
和 param2
.
- 有效:
topic { param1, param2 }, body { param1, param2 }
- 有效:
topic { param1 }, body { param1 }
但它不能没有 topic
只有 param1
和 body 都有,也不能有 topic
有两者和 body 只有 param2
:
- 无效:
topic { param1, param2 }, body { param1 }
- 无效:
topic { param1}, body { param1, param2 }
因为一个节点的内容依赖于另一个节点的内容,我无法使用 dependencies
关键字或 if-then-else
构造,所以我尝试使用oneOf
,并提供有效子模式的列表,其中引用了字段的 one_param
和 both_params
版本,如下所示:
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
验证器的行为不是我所期望的:它在两个参数的情况下都失败,并成功地验证了一个参数或不匹配参数的情况。
为什么我的验证模式没有像我解释的那样工作?
这是我为此编写的完整测试:
good_1
个案验证失败
good_2
、bad_1
和 bad_2
个案例已成功验证
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
good_1 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
good_2 = {
"request": {
"topic": {
"param1": "bleep beep"
},
"message": {
"param1": "bleep beep message"
}
}
}
bad_1 = {
"request": {
"topic": {
"param1": "bleep beep",
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message with no matching topic"
}
}
}
bad_2 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop topic with no matching message"
},
"message": {
"param1": "bleep beep message"
}
}
}
validate(good_1, test_schema) # should validate
validate(good_2, test_schema) # should validate
validate(bad_1, test_schema) # should fail
validate(bad_2, test_schema) # should fail
对于 oneOf
,数组中的每一项(子模式)都应用于数据。如果您测试 oneOf
中的每个单独的子模式,会发生什么?
你会发现两者都是有效的!
您的 "one_param"
架构需要确保包含 param2
会导致它失败。您可以使用 additionalProperties
来执行此操作...
{
"type": "object",
"properties": {
"param1": {
"type": "string"
}
},
"required": [
"param1"
],
"additionalProperties": false
}
我认为您假设只允许在 properties
中定义的属性,但事实并非如此,因此您还需要在 required
.
中定义它们
您可以通过在 https://jsonschema.dev 上尝试架构来了解它是否有效。我已经使用更新的架构和实例预加载了 link。
顺便说一句,您可以使用 definitions
和 $ref
来避免重复子模式,如果您希望将模式保存到单个 json 文件中。
我正在尝试使用 jsonschema 3.0.1
验证 Python 中的 json
有效载荷,大致看起来像这样(简化了麻烦的部分):
{
"request": {
"topic": {
"param1": "bleep beep topic",
"param2": "bloop boop topic"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
一个有效的请求应该有两个字段:一个topic
和匹配的message
.
它们中的每一个都可以仅包含 param1
或 两者 param1
和 param2
.
- 有效:
topic { param1, param2 }, body { param1, param2 }
- 有效:
topic { param1 }, body { param1 }
但它不能没有 topic
只有 param1
和 body 都有,也不能有 topic
有两者和 body 只有 param2
:
- 无效:
topic { param1, param2 }, body { param1 }
- 无效:
topic { param1}, body { param1, param2 }
因为一个节点的内容依赖于另一个节点的内容,我无法使用 dependencies
关键字或 if-then-else
构造,所以我尝试使用oneOf
,并提供有效子模式的列表,其中引用了字段的 one_param
和 both_params
版本,如下所示:
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
验证器的行为不是我所期望的:它在两个参数的情况下都失败,并成功地验证了一个参数或不匹配参数的情况。
为什么我的验证模式没有像我解释的那样工作?
这是我为此编写的完整测试:
good_1
个案验证失败good_2
、bad_1
和bad_2
个案例已成功验证
from jsonschema import validate
one_param = {
"type": "object",
"properties": {
"param1": {
"type": "string",
}
},
"required": ["param1"]
}
both_params = {
"type": "object",
"properties": {
"param1": {
"type": "string",
},
"param2": {
"type": "string",
}
},
"required": ["param1", "param2"]
}
test_schema = {
"type": "object",
"properties": {
"request": {
"oneOf": [
{
"type": "object",
"properties": {
"topic": one_param,
"message": one_param
},
"required": ["topic", "message"]
},
{
"type": "object",
"properties": {
"topic": both_params,
"message": both_params
},
"required": ["topic", "message"]
}
],
}
}
}
good_1 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}
good_2 = {
"request": {
"topic": {
"param1": "bleep beep"
},
"message": {
"param1": "bleep beep message"
}
}
}
bad_1 = {
"request": {
"topic": {
"param1": "bleep beep",
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message with no matching topic"
}
}
}
bad_2 = {
"request": {
"topic": {
"param1": "bleep beep",
"param2": "bloop boop topic with no matching message"
},
"message": {
"param1": "bleep beep message"
}
}
}
validate(good_1, test_schema) # should validate
validate(good_2, test_schema) # should validate
validate(bad_1, test_schema) # should fail
validate(bad_2, test_schema) # should fail
对于 oneOf
,数组中的每一项(子模式)都应用于数据。如果您测试 oneOf
中的每个单独的子模式,会发生什么?
你会发现两者都是有效的!
您的 "one_param"
架构需要确保包含 param2
会导致它失败。您可以使用 additionalProperties
来执行此操作...
{
"type": "object",
"properties": {
"param1": {
"type": "string"
}
},
"required": [
"param1"
],
"additionalProperties": false
}
我认为您假设只允许在 properties
中定义的属性,但事实并非如此,因此您还需要在 required
.
您可以通过在 https://jsonschema.dev 上尝试架构来了解它是否有效。我已经使用更新的架构和实例预加载了 link。
顺便说一句,您可以使用 definitions
和 $ref
来避免重复子模式,如果您希望将模式保存到单个 json 文件中。