Python JSON 架构:验证数字或空值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22565005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 01:10:49  来源:igfitidea点击:

JSON Schema: validate a number-or-null value

pythonjsonapivalidationjsonschema

提问by Adam Matan

Is there a way to enable a JSON schema property to be either a number or null?

有没有办法让 JSON 架构属性成为数字或null

I am building an API which contains a headingattribute. Can be a number between 0 (inclusive) and 360 (exclusive), or null, so the following inputs are OK:

我正在构建一个包含heading属性的 API 。可以是 0(包含)和 360(不包含)之间的数字,也可以为 null,因此以下输入是可以的:

{"heading": 5}
{"heading": 0}
{"heading": null}
{"heading": 12}
{"heading": 120}
{"heading": null}

And the following inputs are erroneous:

以下输入是错误的:

{"heading": 360}
{"heading": 360.1}
{"heading": -5}
{"heading": false}
{"heading": "X"}
{"heading": 1200}
{"heading": false}

Addendum:

附录:

anyOfis clearly the right answer. Adding the full schema for clarity.

anyOf显然是正确的答案。为清楚起见,添加完整架构。

Schema

架构

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "heading": {
        "anyOf": [
          {"type": "number"},
          {"type": "null"}
        ]
      }
    }
}

采纳答案by fiddur

In draft-04, you would use the anyOf directive:

在 Draft-04 中,您将使用 anyOf 指令:

{
  "anyOf": [
    {
      "type": "number",
      "minimum": 0,
      "maximum": 360,
      "exclusiveMaximum": true
    },
    {
      "type": "null"
    }
  ]
}

You could also use "type": ["number", "null"] as Adam suggests, but I think anyOf is cleaner (as long as you use a draft-04 implementation), and ties the minimum and maximum declaration to the number explicitly.

您也可以按照 Adam 的建议使用 "type": ["number", "null"],但我认为 anyOf 更简洁(只要您使用 Draft-04 实现),并将最小和最大声明与数字联系起来明确地。

Disclaimer: I don't know anything about the python implementation, my answer is about json schema.

免责声明:我对 python 实现一无所知,我的答案是关于 json 模式。

回答by Adam Matan

The trick is using a type array. Instead of:

诀窍是使用类型数组。代替:

"type": "number"

Use:

用:

"type": ["number", "null"]

The following code enforces a number-or-null policy, plus numerical restrictions if the value is a number:

以下代码强制执行数字或空策略,如果值为数字,则加上数字限制:

from jsonschema import validate
from jsonschema.exceptions import ValidationError
import json

schema=json.loads("""{
  "$schema": "http://json-schema.org/schema#",
  "description": "Schemas for heading: either a number within [0, 360) or null.",
  "title": "Tester for number-or-null schema",
  "properties": {
    "heading": {
      "type": ["number", "null"],
      "exclusiveMinimum": false,
      "exclusiveMaximum": true,
      "minimum": 0,
      "maximum": 360
    }
  }
}""")

inputs = [
{"heading":5}, {"heading":0}, {"heading":360}, {"heading":360.1},
{"heading":-5},{"heading":None},{"heading":False},{"heading":"X"},
json.loads('''{"heading":12}'''),json.loads('''{"heading":120}'''),
json.loads('''{"heading":1200}'''),json.loads('''{"heading":false}'''),
json.loads('''{"heading":null}''')
]

for input in inputs:
    print "%-30s" % json.dumps(input),
    try:
        validate(input, schema)
        print "OK"
    except ValidationError as e:
        print e.message

Which gives:

这使:

{"heading": 5}                 OK
{"heading": 0}                 OK
{"heading": 360}               360.0 is greater than or equal to the maximum of 360
{"heading": 360.1}             360.1 is greater than or equal to the maximum of 360
{"heading": -5}                -5.0 is less than the minimum of 0
{"heading": null}              OK
{"heading": false}             False is not of type u'number', u'null'
{"heading": "X"}               'X' is not of type u'number', u'null'
{"heading": 12}                OK
{"heading": 120}               OK
{"heading": 1200}              1200.0 is greater than or equal to the maximum of 360
{"heading": false}             False is not of type u'number', u'null'
{"heading": null}              OK

回答by Vadim Samokhin

This answer doesn't regard JSON Schema, but it can be useful if you'd want to consider some alternatives in the future.

这个答案不考虑 JSON Schema,但如果您想在未来考虑一些替代方案,它会很有用。

If you only want a single validatable element out of several to be successful, you could write this directly:

如果您只希望多个可验证元素中的一个成功,则可以直接编写:

Validatable<?> validatableElement =
    new OneOf(
        "global",
        new ErrorStub("This field should be either integer, or null, or absent at all"),
        new AsInteger(
            new Required(
                new IndexedValue("header", json)
            )
        ),
        new IsAbsent<>(
            new IndexedValue("header", json)
        )
    );

If there is a value and it's integer, then the result will be the following:

如果有一个值并且它是整数,那么结果将如下所示:

Result<?> result = validatableElement.result();
assertTrue(result.isSuccessful());
assertEquals(
    24,
    result.value().raw()
);

If no header passed or it's null, then the result will look like that:

如果没有标头传递或者它为空,那么结果将如下所示:

assertTrue(result.isSuccessful());
assertFalse(result.value().isPresent());

For more about this approach and a library implementing it, check out quick start entrywith more examples.

有关此方法和实现它的库的更多信息,请查看包含更多示例的快速入门条目