【问题标题】:jsonschema - oneOf keyword behaves unexpectedlyjsonschema - oneOf 关键字的行为异常
【发布时间】:2019-08-12 14:26:48
【问题描述】:

我正在尝试使用 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两者 param1param2

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

但它不能既没有topic 和只有param1 的正文,也不能有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

【问题讨论】:

    标签: json python-3.x validation jsonschema python-jsonschema


    【解决方案1】:

    使用oneOf,数组中的每个项目(一个子模式)都应用于数据。如果您测试 oneOf 中的每个单独的子模式,会发生什么?

    你会发现两者都是有效的!

    您的"one_param" 架构需要确保包含param2 会导致它失败。您可以使用additionalProperties 来执行此操作...

    {
      "type": "object",
      "properties": {
        "param1": {
          "type": "string"
        }
      },
      "required": [
        "param1"
      ],
      "additionalProperties": false
    }
    

    我认为您假设只允许在 properties 中定义的属性,但事实并非如此,因此您还需要在 required 中定义它们。

    您可以通过尝试https://jsonschema.dev 上的架构来查看此功能。我已经使用更新的架构和实例预加载了链接。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多