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.