JSON Schema: validate a number-or-null value JSON Schema: validate a number-or-null value json json

JSON Schema: validate a number-or-null value


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

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

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


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 validatefrom jsonschema.exceptions import ValidationErrorimport jsonschema=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


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

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 entry with more examples.