Based on the previous answer I built a scheme that would meet my requirements. The question and the answer to it can be seen here.
The resulting scheme:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"virtual"
],
"properties": {
"virtual": {
"type": "array",
"items": {
"type": "object",
"required": [
"type",
"path",
"entity",
"nodes"
],
"properties": {
"type": {
"type": "string"
},
"path": {
"type": "string"
},
"entity": {
"enum": ["pde", "topaz"]
}
},
"anyOf": [
{
"properties": {
"entity": {"const": "pde"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"title": "The Items Schema",
"required": [
"id",
"type",
"address",
"nozzles"
],
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"address": {
"type": "integer"
},
"nozzles": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
}
}
},
{
"properties": {
"entity": {"const": "topaz"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"uid",
"utype",
"uaddress",
"unozzles"
],
"properties": {
"uid": {
"type": "integer"
},
"utype": {
"type": "string"
},
"uaddress": {
"type": "string"
},
"unozzles": {
"type": "boolean"
}
}
}
}
}
}
]
}
}
}
}
And JSON:
{
"virtual": [
{
"type": "bus",
"path": "VBUS1",
"entity": "pde",
"nodes": [
{
"id": "vrt_1",
"type": "dispenser",
"address": 1,
"nozzles": [1, 2, 3]
},
{
"id": "vrt_2",
"type": "dispenser",
"address": 2,
"nozzles": [4, 5, 3]
}
]
},
{
"type": "bus",
"path": "VBUS2",
"entity": "topaz",
"nodes": [
{
"uid": 1,
"utype": "dispenser",
"uaddress": "false",
"unozzles": true
},
{
"uid": 2,
"utype": "dispenser",
"uaddress": "true",
"unozzles": false
}
]
}
]
}
The following problem appeared. When type=bus JSON has path and entity fields. But, if type=io the path and entity fields are missing and the node field looks different from the above two.
Hence I need to have anyOf that would track the value of the type field and another anyOf that would work for type=bus.
I will try to explain more clearly. It is necessary to track the value of the type field and if it is equal to bus, then the path and entity fields appear. Depending on the value of entity, the node field has a certain structure (exactly what is written in the diagram above).
I tried to make a schema with nested anyOf:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"virtual"
],
"properties": {
"virtual": {
"type": "array",
"items": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": ["bus", "io"]
}
},
"anyOf": [
{
"properties": {
"type": {"const": "bus"},
"path": { "type": "string" },
"entity": { "enum": ["topaz", "pde"] }
},
"anyOf":[
{
"properties":{
"entity": {"const": "pde"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"type",
"address",
"nozzles"
],
"properties": {
"id": { "type": "string" },
"type": { "type": "string" },
"address": { "type": "integer" },
"nozzles": {
"type": "array",
"items": { "type": "integer" }
}
}
}
}
}
},
{
"entity": {"const": "topaz"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"uid",
"utype",
"uaddress",
"unozzles"
],
"properties": {
"uid": { "type": "integer" },
"utype": { "type": "string" },
"uaddress": { "type": "string" },
"unozzles": { "type": "boolean" }
}
}
}
}
]
},
{
"properties": {
"type": {"const": "io"},
"nodes": {
"type": "array",
"items":{
"type": "object",
"required": [
"num",
"key",
"title",
"path"
],
"properties": {
"num": { "type": "integer" },
"key": { "type": "integer" },
"title": { "type": "string" },
"path": { "type": "string" }
}
}
}
}
}
]
}
}
}
}
Example of checking the scheme on the site
But as expected, the scheme accepts even those schemes that should not be accepted.
An example of a non-valid schema. There is no required id field for type=bus, entity=pde. There is no mandatory uid field for type=bus, entity=topaz. It feels like the second nested anyOf is ignored.
{
"virtual": [
{
"type": "bus",
"path": "VBUS1",
"entity": "pde",
"nodes": [
{
"not_id": "vrt_1",
"type": "dispenser",
"address": 1,
"nozzles": [
1,
2,
3
]
},
{
"id": "vrt_2",
"type": "dispenser",
"address": 2,
"nozzles": [
4,
5,
3
]
}
]
},
{
"type": "bus",
"path": "VBUS2",
"entity": "topaz",
"nodes": [
{
"not_uid": 1,
"utype": "dispenser",
"uaddress": "false",
"unozzles": true
},
{
"uid": 2,
"utype": "dispenser",
"uaddress": "true",
"unozzles": false
}
]
},
{
"type": "io",
"nodes": [
{
"num": 1,
"key": 123,
"title": "123",
"path": "123"
}
]
}
]
}
Check the validity of the incorrect JSON.
In this case, anyOf for the type field works as expected. I assume that this problem appeared again because of the wrong layout of the scheme, but I could not find information on the Internet on nested anyOf.
When trying to insert all checks into one anyOf everything works as intended.
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"virtual"
],
"properties": {
"virtual": {
"type": "array",
"items": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": { "enum": ["bus", "io"] }
},
"anyOf": [
{
"properties": {
"type": {"const": "bus"},
"path": { "type": "string" },
"entity": {"const": "pde"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"title": "The Items Schema",
"required": [
"id",
"type",
"address",
"nozzles"
],
"properties": {
"id": { "type": "string" },
"type": { "type": "string" },
"address": { "type": "integer" },
"nozzles": {
"type": "array",
"items": { "type": "integer" }
}
}
}
}
}
},
{
"properties": {
"type": {"const": "bus"},
"path": { "type": "string" },
"entity": {"const": "topaz"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"uid",
"utype",
"uaddress",
"unozzles"
],
"properties": {
"uid": { "type": "integer" },
"utype": { "type": "string" },
"uaddress": { "type": "string" },
"unozzles": { "type": "boolean" }
}
}
}
}
},
{
"properties": {
"type": {"const": "io"},
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"num",
"key",
"title",
"path"
],
"properties": {
"num": { "type": "integer" },
"key": { "type": "integer" },
"title": { "type": "string" },
"path": { "type": "string" }
}
}
}
}
}
]
}
}
}
}
But:
- This scheme looks quite dirty
- It's not exactly what I'd like to see
The JSON schema itself, for which you want to create a schema:
{
"virtual": [
{
"type": "bus",
"path": "VBUS1",
"entity": "pde",
"nodes": [
{
"id": "vrt_1",
"type": "dispenser",
"address": 1,
"nozzles": [1, 2, 3]
},
{
"id": "vrt_2",
"type": "dispenser",
"address": 2,
"nozzles": [4, 5, 3]
}
]
},
{
"type": "bus",
"path": "VBUS2",
"entity": "topaz",
"nodes": [
{
"uid": 1,
"utype": "dispenser",
"uaddress": "false",
"unozzles": true
},
{
"uid": 2,
"utype": "dispenser",
"uaddress": "true",
"unozzles": false
}
]
},
{
"type": "io",
"nodes": [
"num": 4,
"key": 123456,
"title": "io",
"path": "default"
]
}
]
}
Full JSON has a rather complex structure and only part of it is represented here. Hence I would like to understand how to structure such things correctly (understand the idea itself, and preferably see an example of the correct scheme. At least schematic).
So, to summarize. I need to understand how any Of can be implemented in one of the anyOf variants. Is it feasible? And, if so, where can I see examples and instructions for compiling such schemes? If not, is there any workaround?