The fields in nodes depend on the value of entity. That is, if entity = "pd", then nodes has some fields, while entity = " top " - nodes has completely different fields, despite the fact that they are strictly required. For some reason, the JSON string is accepted by the valid schema, even if there are no fields defined in nodes as required. I already entire head broke, where can be mistake in the most scheme?
JSON-schema:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"required": [
"virtual"
],
"properties": {
"virtual": {
"$id": "#/properties/virtual",
"type": "array",
"title": "The Virtual Schema",
"items": {
"$id": "#/properties/virtual/items",
"type": "object",
"title": "The Items Schema",
"required": [
"type",
"path",
"entity",
"nodes"
],
"properties": {
"type": {
"$id": "#/properties/virtual/items/properties/type",
"type": "string",
"title": "The Type Schema",
"default": "",
"examples": [
"bus"
],
"pattern": "^(.*)$"
},
"path": {
"$id": "#/properties/virtual/items/properties/path",
"type": "string",
"title": "The Path Schema",
"default": "",
"examples": [
"VBUS2"
],
"pattern": "^(.*)$"
},
"entity": {
"$id": "#/properties/virtual/items/properties/entity",
"type": "string",
"title": "The Entity Schema",
"default": "",
"examples": [
"topaz"
],
"enum": ["pde", "topaz"],
"pattern": "^(.*)$"
},
"nodes": {
"$id": "#/properties/virtual/items/properties/nodes",
"type": "array",
"title": "The Nodes Schema",
"items": {
"$id": "#/properties/virtual/items/properties/nodes/items",
"type": "object",
"title": "The Items Schema"
}
}
}
}
}
},
"anyOf": [
{
"if": {
"properties": { "virtual": { "properties": { "entity": { "const": "topaz" } } } }
},
"then": {
"properties": {
"virtual": {
"properties": {
"nodes": {
"items": {
"required": [
"uid",
"utype",
"uaddress",
"unozzles"
],
"properties": {
"uid": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/uid",
"type": "integer",
"title": "The Uid Schema",
"default": 0,
"examples": [
1
]
},
"utype": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/utype",
"type": "string",
"title": "The Utype Schema",
"default": "",
"examples": [
"dispenser"
],
"pattern": "^(.*)$"
},
"uaddress": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/uaddress",
"type": "string",
"title": "The Uaddress Schema",
"default": "",
"examples": [
"false"
],
"pattern": "^(.*)$"
},
"unozzles": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/unozzles",
"type": "boolean",
"title": "The Unozzles Schema",
"default": false,
"examples": [
false
]
}
}
}
}
}
}
}
}
},
{
"if": {
"properties": { "virtual": { "properties": { "entity": { "const" : "pde" } } } }
},
"then": {
"properties": {
"virtual": {
"properties": {
"nodes": {
"items": {
"required": [
"id",
"type",
"address",
"nozzles"
],
"properties": {
"id": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/id",
"type": "string",
"title": "The Id Schema",
"default": "",
"examples": [
"vrt_1"
],
"pattern": "^(.*)$"
},
"type": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/type",
"type": "string",
"title": "The Type Schema",
"default": "",
"examples": [
"dispenser"
],
"pattern": "^(.*)$"
},
"address": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/address",
"type": "integer",
"title": "The Address Schema",
"default": 0,
"examples": [
1
]
},
"nozzles": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles",
"type": "array",
"title": "The Nozzles Schema",
"items": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles/items",
"type": "integer",
"title": "The Items Schema",
"default": 0,
"examples": [
1,
2,
3
]
}
}
}
}
}
}
}
}
}
}
]
}
This JSON is valid:
{
"virtual": [
{
"type": "bus",
"path": "VUS1",
"entity": "pde",
"nodes": [
{
"id": "vrt_1",
"type": "string",
"address": 1,
"nozzles": [1, 2, 3]
},
{
"id": "vrt_2",
"type": "string",
"address": 2,
"nozzles": [1, 2, 3]
}
]
},
{
"type": "bus",
"path": "VUS2",
"entity": "topaz",
"nodes": [
{
"uid": 1,
"utype": "string",
"uaddress": "false",
"unozzles": false
},
{
"uid": "vrt_1",
"utype": "string",
"uaddress": "false",
"unozzles": false
}
]
}
]
}
And this JSON should not be applied, but is considered valid:
{
"virtual": [
{
"type": "bus",
"path": "VUS1",
"entity": "pde",
"nodes": [
{
"id_not_valid": "failure",
"type": 1,
"address": false,
"nozzles": [1, 2, 3]
},
{
"id": "vrt_2",
"type": "string",
"address": false,
"nozzles": [1, 2, 3]
}
]
},
{
"type": "bus",
"path": "VUS2",
"entity": "topaz",
"nodes": [
{
"uid_not_valid": "failure",
"utype": 1,
"uaddress": "false",
"unozzles": false
}
]
}
]
}
In theory, the second JSON should not be validated. For several reasons:
For entity= "pd", the required fields are "id", "type"," address "and"nozzles". In the second line of JSON instead the field "id" is replaced by the field "id_not_valid" - > the obligatory field " id " is absent and validation has to end in failure. The same for entity="top" - "the uid" is replaced by "id_not_valid"
For entity= "pd", the address field is of type token, in the second JSON line it is set to false, which corresponds to the type "boolean", but validation still takes place (the same if you assign an array or string value to address). For entity="top" type, the type is string, but the integer value 1 assigned to it is also assumed by the validator to be the correct string.
But the online validators on the links below say that everything is OK and both JSON conform to the scheme.
The first site
Second site
The third website
So I believe there is an error in the scheme.
The scheme itself was made by this example Example of JSON schema compilation
Any comments and tips on fixing JSON-schema, please
The schema is malformed.
(I'm ignoring the fact that the schema states entity should be "pde" or "topaz", but the instances have "pd" and "top". I assume this is a typo.)
Inside the anyOf, you have two items, each with an if conditional keyword. The schema presented by this keyword is
{
"properties": {
"virtual": {
"properties": {
"entity": {
"const": "topaz"
}
}
}
}
}
This is saying that if virtual has an entity property, then it should be "topaz". But the way that properties works is that it only fails validation if the instance is an object. However in #/properties, you declare that virtual should be an an array of objects where each item contains an entity property.
Since virtual is an array in your instance, none of the if condition keywords in the anyOf pass, so they defer to the else keywords for those subschemas, which don't exist (so the pass by default). This results in both subschemas for the anyOf passing.
I think what you're trying to do is validate each of the items inside the array based on the value of the entity property for that item. This means that you could have both a pde item and a topaz item in the array.
To do this you need to isolate where the variance is. In your case, it's the item level inside the virtual array. This is where you need to put your anyOf.
So you'll want to add your anyOf to #/properties/virtual/items. This is the only point in the schema where an if/then construct can key off of the entity property and enforce the nodes property.
Edit Things I would change
Remove all of the internal $id declarations. They only reiterate the location in the document and provide no additional functionality.
Remove the type and pattern declarations from entity. enum is sufficient here because it declares that the values must be one of the items in the array. Since these are both strings and match the given pattern, those keywords are redundant.
Move the anyOf alongside the properties keyword inside virtual and change it to a oneOf. This is the most specific location where you can access both the entities property and the nodes property. Changing it to a oneOf ensures that exactly one can be true.
Drop the if/then construct and just include the constant value in the then portion.
In the end, it would be structured something like this:
{
... ,
"properties": {
"virtual": {
"type": "array",
"title": "The Virtual Schema",
"items": {
"type": "object",
"title": "The Items Schema",
"required": [ "type", "path", "entity", "nodes" ],
"properties": {
"type": { ... },
"path": { ... },
"entity": {
"title": "The Entity Schema",
"default": "",
"examples": [
"topaz"
],
"enum": ["pde", "topaz"]
}
},
"oneOf": [
{
"properties": {
"entity": {"const": "topaz"},
"nodes": { ... }
}
},
{
"properties": {
"entity": {"const": "pde"},
"nodes": { ... }
}
}
]
}
}
}
}
Here, we're declaring that the items within the virtual array must be objects requiring 4 properties: type, path, entity, and nodes. We explicitly define type, path, entity using the properties keyword. But we conditionally define the nodes property using the oneOf and specifying a constant value for the entity property in each case.
I receive the following items in a JSON Array
{locations: [{locId: "1", locName: "ST1"}, {locId: "2", locName: "ST2"}, {locId: "3", locName: "ST3"}]}
My requirement is that inside locations the value for locName has to be one of ST1, ST2, or ST3 (I don't care about locId). How do I enforce this in the JSONSchema. I saw you can use array but how do I specify that an object\item of the array should have one of the pre-defined values for a particular property.
You can use the enum keyword to restrict the allowed values for a given property:
"locName": {
"type": "string",
"enum": ["ST1", "ST2", "ST3"]
}
Complete schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"locations": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"locId": {
"type": "string"
},
"locName": {
"type": "string",
"enum": ["ST1", "ST2", "ST3"]
}
},
"required": [
"locId",
"locName"
]
},
]
}
},
"required": [
"locations"
]
}
I want to validate my API json response like this:
{
"code": 0,
"results": [
{"type":1, "abc": 123},
{"type":2, "def": 456}
]
}
I want to validate the objects within results to have a "abc" field when its type is 1, and "def" field when its type is 2. The results may contain arbitrary number of type1 and type2 objects.
Can I specify this in jsonschema? Or must I use a generic validator for elements in results and do validation myself?
You can do this using the anyOf keyword.
An instance validates successfully against this keyword if it validates successfully against at least one schema defined by this keyword's value.
http://json-schema.org/latest/json-schema-validation.html#anchor85
You need to define both types of items and then use anyOf To describe the array items for "results".
{
"type": "object",
"properties": {
"code": { "type": "integer" },
"results": {
"type": "array",
"items": { "$ref": "#/definitions/resultItems" }
}
},
"definitions": {
"resultItems": {
"type": "object",
"anyOf": [
{ "$ref": "#/definitions/type1" },
{ "$ref": "#/definitions/type2" }
]
},
"type1": {
"properties": {
"type": { "enum": [1] },
"abc": { "type": "integer" }
},
"required": ["abc"]
},
"type2": {
"properties": {
"type": { "enum": [2] },
"def": { "type": "integer" }
},
"required": ["def"]
}
}
}
Its looking like both works fine with my input validation code. Then what is the exact difference?
Schema with oneof
[{
"id": "MyAction",
"oneOf": [{ "$ref": "A1" },
{ "$ref": "A2" }]
},
{
"id": "A1",
"properties": {
"class1": { "type": "string"},
"class2": { "type": "string"}
}
},
{
"id": "A2",
"properties": {
"class2": { "type": "string"},
"class3": { "type": "string"}
}
}
]
Schema with anyof
[{
"id": "MyAction",
"anyOf": [{ "$ref": "A1" },
{ "$ref": "A2" }]
},
{
"id": "A1",
"properties": {
"class1": { "type": "string"},
"class2": { "type": "string"}
}
},
{
"id": "A2",
"properties": {
"class2": { "type": "string"},
"class3": { "type": "string"}
}
}
]
If you look at the JSON Schema documentation, it says:
anyOf:
...
An instance validates successfully against this keyword if it
validates successfully against at least one schema defined by this
keyword's value. Note that when annotations are being collected, all
subschemas MUST be examined so that annotations are collected from
each subschema that validates successfully.
oneOf:
...
An instance validates successfully against this keyword if it
validates successfully against exactly one schema defined by this
keyword's value.
Note my emphasis in the above. anyOf means the item must validate against at least one (but possibly more than one) of the schemas. oneOf means it must validate against only one of the schemas.
I am late in the quest but as per my understanding the usage of this keyword depends on the type of the object/parent itself. for example if you are trying to define the type for a single property of the object or the element of an array. take the below example :
{
"title": "Sample JSON Schema",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"definitions": {
"propObjectType1" : {
"name": "string",
"age": "number"
},
"propObjectType2" : {
"name": "string",
"dob": {
"type": "string",
"pattern": "\\d\\d\/\\d\\d\/\\d\\d\\d\\d"
}
}
},
"properties": {
"prop1": {
"type": "string",
"maxLength": 64
},
"prop2": {
"anyOf": [
{
"$ref": "#/definitions/propObjectType1"
},
{
"$ref": "#/definitions/propObjectType2"
}
]
},
"prop3": {
"oneOf": [
{
"$ref": "#/definitions/propObjectType1"
},
{
"$ref": "#/definitions/propObjectType2"
}
]
},
"prop4Array": {
"type": "array",
"items": {
"oneOf": [
{
"$ref": "#/definitions/propObjectType1"
},
{
"$ref": "#/definitions/propObjectType2"
}
]
}
},
"prop5Array": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/propObjectType1"
},
{
"$ref": "#/definitions/propObjectType2"
}
]
}
}
}
}
So in the above definition the prop2 and prop3 are the same (you can use interchangeably anyOf or oneOf) and you can define what ever you are comfortable with. but, in case of array:
when you use anyOf for the items type, the elements can be of any type out of those and the array can contain the mixed items. Means you can have one item of type 1 and another item of type 2.
when you use oneOf for the items type, the elements can be of any type out of those and the array can contain only one type of items. Means all the items must be of the same type (either type 1 or type 2).
I need to create a JSON schema for object that will include java Properties object as one of its properties.
The nested Properties object will be simply list of key=value. Both key and value are of type string.
I failed to find any docs that describe how to define the schema that includes 2 new types.
shall it be something like:
{
"type": "object",
"name": "MyObj",
"properties": {
"prop1": {
"type": "string",
"description": "prop1",
"required": true
},
"props": {
"type": "array",
"items": {
"type": "object"
"properties": {
"key": {
"type": "string",
"description": "key",
"required": true
},
"value": {
"type": "string",
"description": "the value",
"required": true
}
}
"description": "the value",
"required": true
}
}
}
}
The schema you have written (assuming the commas are fixed) describes data of the form:
{
"prop1": "Some string property goes here",
"props": [
{"key": "foo", "value": "bar"},
{"key": "foo2", "value": "bar2"},
...
]
}
If this is what you wanted, then you are already finished.
However, I do wonder why you are using key/value pairs in an array, when you could use a JSON object with string keys instead. Using the additionalProperties keyword, you could have a schema:
{
"type": "object",
"name": "MyObj",
"properties": {
"prop1": {
"type": "string",
"description": "prop1"
},
"props": {
"type": "object",
"additionalProperties": {
"type": "string",
"description": "string values"
}
}
}
}
This describes a data format like:
{
"prop1": "Some string property goes here",
"props": {
"foo": "bar",
"foo2": "bar2"
}
}
At W3 schools (JSON Syntax) you can read how the array should be defined.
There is no schema like the xsd for xml, however i've found an approach on json-schema.org. If you are able to, i'll advice to youse google-GSON library for JSON. You could Store key Value as "id" : "value" and build only one object, containing all requieed pairs:
{ "lang" : "EN" , "color" : "red" }
Your posted model is incorect, you can check it on jsonlint.com
Here is a working version, i'm not sure if the modell is as expected.
{
"type": "object",
"name": "MyObj",
"properties": [
{
"prop1": {
"type": "string",
"description": "prop1",
"required": true
},
"props": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "key",
"required": true
},
"value": {
"type": "string",
"description": "the value",
"required": true
}
},
"description": "the value",
"required": true
}
}
}
]
}