JSON Schema:验证数字或空值

时间:2014-03-21 17:02:51

标签: python json api validation jsonschema

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

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

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

以下输入是错误的:

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

附录:

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

模式

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

3 个答案:

答案 0 :(得分:26)

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

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

您也可以使用“type”:[“number”,“null”],如Adam建议的那样,但我认为anyOf更干净(只要你使用draft-04实现),并将最小和最大声明联系起来明确地说明这个数字。

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

答案 1 :(得分:25)

诀窍是使用类型数组。而不是:

"type": "number"

使用:

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

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

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

给出了:

{"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

答案 2 :(得分:0)

此答案与JSON模式无关,但是如果您将来希望考虑一些替代方法,那么它将很有用。

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

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)
        )
    );

如果有一个值并且它是整数,那么结果将是以下内容:

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

如果没有传递标题或它为null,那么结果将如下所示:

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

有关此方法和实现该方法的库的更多信息,请查看quick start entry并提供更多示例。