Semantics
In this section we present a formal specification of how JSON Schema restrictions are validated against an arbitraty JSON Document. The following rules for formal validations are general, and thus there is no difference between those schemas whose type is specified and that whose type is not specified.
But before specifying the semantics for these validation instances we must define a couple of structures first.
Definitions
Let J be a JSON document. We say that a keyword k appears in J is J contains a key:value pair of the form k: j', for some document j'.
For a JSON Schema S, we use properties(S) to denote all keywords k1, ..., kn
that appear in the key-value pair of the form "properties": {k1: s1 , ... , kn: sn}
in S. The set properties(S) is empty if the keyword properties does not appear in S. Likewise, we use patternProperties(S) to denote all keywords k1, ..., kn
that appear in the key-value pair of the form "patternProperties": {k1: s1 , ... , kn: sn}
in S. The set patternProperties(S) is empty if the keyword properties does not appear in S.
Next, consider the following compatibility table:
type | compatible keywords |
---|---|
string | "type", "minLength", "maxLength", "pattern" |
number | "type", "minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf" |
integer | "type", "minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf" |
boolean | "type" |
null | "type" |
array | "type", "minItems", "maxItems", "items", "uniqueItems" |
object | "type", "properties", "additionalProperties", "required", "minProperties", "maxProperties", "dependencies", "patternProperties". |
We define the function Compatible(J,k) as the function that receives a JSON document J and a key/value pair k of the form key: value
and returns true if key
is a string in the following list:
list of keywords |
---|
"type", "minLength", "maxLength", "pattern", "minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf", "minItems", "maxItems", "items", "uniqueItems", "properties", "additionalProperties", "required", "minProperties", "maxProperties", "dependencies", "patternProperties". |
and key
is compatible with the type of J according to the compatibility table above. Otherwise, Compatible(J,k) returns false. For instance, Compatible(42,"multipleOf": 7) = true, while Compatible(42,"minitems": 4) = false.
JSON Reference
If path is a JSON pointer, we say that rep(path) is the string resulting of replacing first each character ~1
by /
and then each character ~0
by ~
.
Given a JSON document J that is an object, we use J[k] (for a string k) to represent the value of the key value pair in J whose key is k. Likewise, if J is an array, then J[n] (for a natural number n) corresponds to the n-th element of J.
Let J be a JSON document. JSON Pointers are intended to extract a part of J that is specifically indexed by the pointer. Formally, we define the function EVAL() that takes a JSON Document J and a JSON Pointer JPointer and delivers a subset of J:
EVAL(J,JPointer)
returns:
-
J
, if JPointer is the empty string, or -
EVAL(J[rep(key)],JP)
, if J is an object, rep(key) appears in J and JPointer is of the form JP/key, or EVAL(J[n],JP)
, if JPointer is an array with at least n+1 objects and JPointer is of the form JP/n, where n is the base-10 representation of a natural number, or- an error in any other case (for example when the pointer asks for a key that is not in J).
Let R be a JSON Reference of the form "$ref": uriRef
. We extend the function EVAL() to work with arbitrary JSON references. We do it as follows.
EVAL(J,R)
returns:
-
EVAL(J,JPointer)
, ifuriRef
is of the form#/JPointer
, or -
S
, ifuriRef
does not contains the symbol#
and the address inuriRef
succesfully retrieves the schema S, or -
EVAL(S,JPointer)
, ifuriRef
is of the formaddress#/JPointer
and the address inuriRef
succesfully retrieves the schema S, or -
an error in any other case (for example when the address retrieves something that is not a schema).
Let R be again a JSON Reference and J a JSON document. Assume that the JSON schema document that contains R is S. Then we say that J validates against R under S if EVAL(S,R) returns a schema (not an error) and J validates against EVAL(S,R).
Validation
Let S be a JSON Schema and J a JSON document, and assume that the JSON schema document that contains S is D. We say that J validates against S if one of the following holds:
-
One of the key:value pairs in S is a JSON reference R, and J validates against R under D.
-
S does not contain a JSON Reference, and for each key:value pair k in S such that Compatible(J,k) = true we have that J validates against k under S.
Note how we make a special case when J is a JSON reference. In this case, but only if the reference sucessfully retrieves a schema, we ignore all the remaining keywords, and just validate against the schema retrieved by the reference. On the other hand, no document validates agains a reference that returns an error (simply because in this case it is not possible to instantiate the schema)
In turn, let S be a JSON schema, k be a key:value pair in S and J a JSON document. We say that J validates against k under S if one of the following holds:
General Restrictions
- k is
"type": "string"
and J is a string. - k is
"type": "number"
and J is a number. - k is
"type": "integer"
and J is an integer. - k is
"type": "boolean"
and J is a boolean value. - k is
"type": "null"
and J is the value null. - k is
"type": "array"
and J is an array. - k is
"type": "object"
and J is an object. - k is
"type: [t1, ... ,tn]"
and the type of J is ti for some ti in { t1, ..., tn }. - k is
"enum": [j1, ... ,jn]
and J = ji for some ji in { j1, ..., jn }.
Strings Restrictions
- k is of the form
"minLength" : n
and J is a string of length at least n. - k is of the form
"maxLength" : n
and J is a string of length at most n. - k is of the form
"pattern" : "rexp"
and J is a string that matches the regular expression rexp.
Numeric Restrictions
- k is
"multipleOf": r
for some positive decimal number r, and J is a number that is a multpiple of r. - k is
"minimum": r
for some decimal r, and J is a number that is strictly greater than r. - k is
"minimum": r
for some decimal r, J is a number that is equal to r and the pair"exclusiveMinimum": true
is not in S. - k is
"maximum": r
, for some decimal r, and J is a number that is stricly less than r. - k is
"maximum": r
for some decimal r, J is a number that is equal to r and the pair"exclusiveMinimum": true
is not in S.
Arrays Restrictions
- k is
"items": S'
and J is an array such that every element validates against S'. - k is
"items": [s1 , ... , sn]
and J is an array[a1 , ... , am]
such that every element ai validates against si with i ≤ Min(m,n). - k is
"additionalItems": true
and J is an array. - k is
"additionalItems": false
, there is a key:value pair"items": [s1 , ... , sn]
in S and J is an array with at most n elements. - k is
"additionalItems": false
, and either S does not contain a pair with keyword"items"
, or such pair is of the form"items": S'
(that is, the value of items is an object, not an array). - k is
"additionalItems": S'
, S does not contain a pair with keyword"items"
and J is an array such that every element validates against S'. - k is
"additionalItems": S'
and S contains a pair of the form"items": S'
(that is, the value of items is an object, not an array). - k is
"additionalItems": S'
, S has a pair of form"items": [s1 , ... , sn]
, and J is an array[a1 , ... , am]
such that each ai, for i > n, validates against S'. - k is
"minItems": n
and J is an array with at least n elements. - k is
"maxItems": n
and J is an array with at most n elements. - k is
"uniqueItems": true
and J is an array with all elements different from each other.
Object Restrictions
- k is of the form
"properties": {k1: s1 , ... , kn: sn}
and J is an object that for each key-value pair k': j' in J, if k' = ki for some i in [ 1 , ... , n ] then j' satisfies si. - k is of the form
"patternProperties": {rexp1: s1 , ... , rexpn: sn}
and J is an object such that for each key-value pair k': j' in J and every rexpi, i in [ 1 , ... , n ], such that k' is in the language of rexpi, then j' satisfies si. - k is of the form
"required": [k1 , ... , kn]
and each ki appears in J. - k is of the form
"minProperties": n
and J is an object with at least n key:value pairs. - k is of the form
"maxProperties": n
and J is an object with at most n key:value pairs. - k is of the form
"additionalProperties": false
and J is an object such that every keyword in J either belongs to properties(S) or matches at least one of the expressions in patternProperties(S) - k is of the form
"additionalProperties": true
and J is an object - k is of the form
"additionalProperties": S'
and J is an object such that for each key-value pair k': j' in J, with k' not in properties(S) and k' not matching any of the expressions in patternProperties(S), we have that j' validates against S' - k is of the form
"dependencies": {k1: [l1,1 , ... ,l1,m1], ... , kn: [ln,1 , ... ,ln,mn]}
and J is an object such that if ki appears in J then every keyword in [li,1 , ... ,li,mi] appears in J - k is of the form
"dependencies": {k1: s1 , ... , kn: sn}
and J is an object such that if ki appears in J then J must satisfy si
Combinations
- k is of the form
"anyOf": [{Sch1}, {Sch2}, ... ,{Schn}]
and J validates against some Schi, for i=1...n - k is of the form
"allOf": [{Sch1}, {Sch2}, ... ,{Schn}]
and J validates against all of Schi, for i=1...n - k is of the form
"oneOf": [{Sch1}, {Sch2}, ... ,{Schn}]
and J validates against exactly one of Schi, for i=1...n - k is of the form
"not": {Sch}
and J does not validate against Sch