jsonschema - oneOf 关键字行为异常



我正在尝试使用 Python 验证 Python 中的json有效负载,使用jsonschema 3.0.1,大致看起来像这样(简化为麻烦的部分(:

{
"request": {
"topic": {
"param1": "bleep beep topic",
"param2": "bloop boop topic"
},
"message": {
"param1": "bleep beep message",
"param2": "bloop boop message"
}
}
}

有效请求应具有两个字段:topic和匹配message

它们中的每一个都可以仅包含param1,也可以由param1param2组成。

  • 有效:topic { param1, param2 }, body { param1, param2 }
  • 有效:topic { param1 }, body { param1 }

但它既不能有只有param1topic和身体,也不能有两者兼而有之的topic和只有param2的身体:

  • 无效:topic { param1, param2 }, body { param1 }
  • 无效:topic { param1}, body { param1, param2 }

由于一个节点的内容取决于另一个节点的内容,因此我无法使用dependencies关键字或if-then-else构造,因此我尝试使用oneOf,并提供有效子架构的列表,其中包含对该字段的one_paramboth_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_2bad_1bad_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 上尝试架构来了解此功能。我已经使用更新的架构和实例预加载了链接。

顺便说一句,如果您希望将架构保存到单个 json 文件中,您可以使用definitions$ref来避免重复子架构。

最新更新