According to the specification (http://json-schema.org/schema) there is no mutual exclusion among schema keywords.
For example I could create the following schema:
{
"properties" : {
"foo" : {"type" : "string"}
}
"items" : [
{"type" : "integer" },
{"type" : "number" }
]
}
Would this schema validate against both objects and arrays?
If so it would imply an "OR" relationship between keyword.
But if we consider the following schema:
{
"anyOf" : [
{ "type" : "string",},
{ "type" : "integer"}
]
"not" : {
{ "type" : "string",
"maxLength" : 5
}
}
}
The most practical way to interpret it would be an "AND" relationship between anyOf and not keywords.
I could not find any indication in the draft v4 on how keywords logically interact. Can anyone point me to a documentation/standard that would answer this question?
Keywords are always an "AND" relationship. Data must satisfy all keywords from a schema.
The properties and items keywords don't specify the type of the object (you have to use type for that). Instead, they only have meaning for particular types, and are ignored otherwise. So properties actually means:
If the data is an object, then the following property definitions apply...
This means that {"properties":{...}} will match any string, because properties is ignored for values that aren't objects. And items actually means:
If the data is an array, then the following item definitions apply...
So the AND combination looks like:
(If the data is an object, then properties applies) AND (if the data is an array, then items applies)
As the spec clearly dictates, some keywords are only relevant for one particular type of JSON value, or all of them.
So, for instance, properties only applies if the JSON value you validate is a JSON Object. On any JSON value which is NOT an object, it will not apply (another way to understand it is that if the JSON value to validate is not a JSON Object, validation against this keyword will always succeed).
Similarly, items will only apply if the JSON value is a JSON Array.
Now, some other keywords apply for all types; among these are enum, allOf, anyOf, oneOf, type. In each case, the validation rules are clearly defined in the specification.
In short: you should consider what type of value is expected. The easiest way to force a value to be of a given type in a schema is to use type, as in:
"type": "integer"
BUT this keyword will nevertheless be applied INDEPENDENTLY of all others in the validation process. So, this is a legal schema:
{
"type": "integer",
"minItems": 1
}
If an empty JSON Array is passed for validation, it will fail for both keywords:
type because the value is not an array;
minItems because the value is an array but it has zero elements, which is illegal for this particular keyword since it expects one element in the array at least.
Note that the result of validation is totally independent of the order in which you evaluate keywords. That is a fundamental property of JSON Schema. And it is pretty much a requirement that it be so, since the order of members in a JSON Object is irrelevant ({ "a": 1, "b": 2 } is the same JSON Object as { "b": 2, "a": 1 }).
And of course, if only ONE keyword causes validation to fail, the whole JSON value is invalid against the schema.
Related
I'm working with JSON data where one portion of it is a key-value pair collection, where the key is an arbitrary string and the value is an array of strings. I'm trying to write a schema for this, but I'm not sure how to represent arbitrary property names. So for an object like this:
{
"K1": ["V1", "V2", "V3"],
"K2": ["V4", "V5"],
"K3": ["V6", "V7"]
}
What would be the right way to write a JSON schema with the following requirements:
There must be at least one property.
Properties can have any arbitrary string for their name
Every property's associated value must be an array of strings
Every string array must contain at least one string (ie. must not be empty)
You can express a restricted pattern for a property or set of properties with patternProperties; its value is a schema, which is evaluated against the values of all properties that match. So for example, to express a set of rules used for properties that start with a capital letter, you can do "patternProperties": { "^[A-Z]": { ... more rules here .... To define the rules for a property name in terms of a full schema, you can use propertyNames.
To express a schema for the value of all properties, regardless of name, you can use additionalProperties. These rules will not match against any property already matched with a properties or patternProperties.
You can express the minimum number of properties with minProperties.
You can express the rules for all items in an array with items. And minItems can be used to express the minimum allowable number of items.
The schema for your data can be expressed by:
{
"type": "object",
"minProperties": 1,
"additionalProperties": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
}
}
https://json-schema.org/understanding-json-schema/reference/object.html
https://json-schema.org/understanding-json-schema/reference/array.html
Problem:
The requirement to allow only those property Names in an object which are part of an array value of another property in the schema (another property's value dependant property names).
Detailed Explanation:
I have the following JSON:
{
"validResources":["ip","domain","url"],
"resources":
{
"ip" : "192.168.1.1",
"domain" : "www.example.com",
}
}
I would want to write a JSON schema that allows only those keys in "resources" which are part of the array list value of "validResources".
The above JSON is a valid JSON as the "ip" and "domain" keys are actually part of the array items which is a value of the property "validResources".
However, the below JSON should return an error as "file" is not a valid resource as it is not part of the "validResorces" array.
{
"validResources":["ip","domain","url"],
"resources":
{
"ip" : "192.168.1.1",
"file" : "file://etc/passwd" <= No such resource in "validResources"
}
}
What I have tried ?
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type" : "object",
"properties" : {
"validResources" : { "type" : "array",
"minItems" : 1,
"uniqueItems" : true
},
"resources":{
"type":"object",
===Unable to proceed beyond this ===
}
},
}
Other Searches:
I checked propertyNames, however, it can derive only from another schema or have a regex pattern defined as part of its schema. But in this case, the propertyNames / keys within "resources" are dependent on values of the "validResources" property which are not known prior hand and "resources" should allow only those strings/names as its properties which are part of values in array list of "validResources".
There is a pending issue somewhat similar to this question here.
Such a problem cannot be solved as on date with json schema where draft 7 being the latest draft while writing this post.
This question also relates to multiple issues already mentioned in github issues of json-schema spec. Apparently a proposal related to solving such issue is being tracked actively here.
Since this deals with lookup from the value of instance of json schema and not the structural validation alone (which has been the primary motive of existence of json schema standard as on date), this probably has to be dealt differently as of now until next draft comes or the mentioned issue is taken up.
Here is the desired schema and json for illustration purpose. Please see the link below.
JSON Schema and JSON
{
"id": "123" ,
"ts": "1234567890",
"complex_rules":
[
{
"type":"admin",
"rule":{
"rights":"all",
"remarks": "some admin remarks"
}
},
{
"type":"guest",
"rights": "limited"
},
{
"type":"anonymous",
"rights": "blocked"
}
]
}
The 'complex_rules' is an array of json object:
With type either be a : "admin", "guest", "anonymous" and the 'type' attribute is MANDATORY.
Each object in array can have its own structure, but the type can be either of: "admin", "guest", "anonymous" only. No other type attribute is acceptable.
The conditions to evaluate:
The type of object in the array cannot re-occur in the array. (I know this seems to be not possible, so we can ignore this)
If attribute "rights" in the {type=admin object} with any value, then we cannot have "rights": "limited" or any value in {type=guest object}. The JSON Schema validation must complain about this.
Another twist, either object {type":"guest"}or {type":"anonymous"} can exist. Both types cannot coexist along with other types.
----Update
The above link is the solution this question.
In regards to 1 and 2:
You need to use a combination of if, then, and not keywords to construct the logic you require with the correct level of applicability.
In regards to 3:
The type of object in the array cannot re-occur in the array. (I know
this seems to be not possible, so we can ignore this)
Right, that's correct, it's not possible as of draft-7 JSON Schema.
Consider this example:
"allOf": [
{"$ref": "test-address-prefix-types-base.json#"},
{
"properties": {}, "additionalProperties" : false
}
]}
When I validate this with Java schema validator, I get error saying:
"keyword":"additionalProperties","message":"object instance has properties which are not allowed by the schema: [\"attributes\",\"type\"]"}]
but the same JSON object validated against the base schema (test-address-prefix-types-base) passes without error.
The referenced schema (base one) doesn't have additionalProperties set.
This is the json message I am using:
String message = "{\"data\":{\"attributes\":{" +
"\"notation\": \"A\"," +
"\"prefixType\": \"A\"}" +
",\"type\":\"test-address-prefix-types\"}}";
Have I missed anything in schema?
Thanks
Your schema could be expanded this way:
allof: It must validate independently against two schemas:
First one with arbitrary properties linked through ref.
The second one which does not allow any property "additionalProperties" : false except those defined in the empty set "properties" : {}. In other words, it can not have any property.
This problem may be solved in draft-5 of the standard. More on this in the following SO question.
I have two fields in my schema - one is a required property called "name" and the other is optional (used to define a sorting property) called "nameSort" and I want to express
If the "nameSort" field is defined, the "name" field should also be defined as the same value.
Is it possible to express such an "inter-element" constraint with JSON schema? My cursory read of JSON Schema here http://json-schema.org/latest/json-schema-validation.html says no.
Old question, but this can now be done with json schema v5/v6 using a combination of the constant and $data (JSON pointer or relative JSON pointer) keywords.
Example:
"properties": {
"password": { "type": "string" },
"password_confirmation": { "const": { "$data": "1/password" } }
}
Where "1/password" is a relative JSON pointer saying "go up one level, then look up the key password".
You can express one property must be defined when another is present, e.g.:
{
"type": "object",
"dependencies": {
"nameSort": ["name"]
}
}
However, you cannot specify that two properties must have equal values.
Also, why do you have a separate property at all, if it's always going to be equal? And if it's always equal, could you just have a boolean flag to reduce redundancy?