I am trying to define a json schema which has a common enum type for a number of objects and then depending on which enum is selected, define the possible combinations of enums and also additional elements that are needed. The example has FurnitureData with {IDNumber, Color, Furniture Type} and then depending on the Type selected from a enum list, gets a function assigned with different enums. I also put in an example of "Person assigned" as an extra element.
I think I did this correctly using anyof and const. But, when I test with XMLSpy Pro 2020, it generates invalid json examples and also when I try to validate an invalid example, it passes.... so, 1) did I express this well ? 2) what am I doing wrong ? 3) is there a better way ? 4) Is it the tool or the json schema ? Please help.
JSON Schema :
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Comment describing your JSON Schema",
"type": "object",
"properties": {
"FurnitureData": {
"type": "array",
"items": {
"type": "object",
"properties": {
"IDNumber": {
"type": "object",
"description": "Unique identifier",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"maxLength": 16
},
"readOnly": {
"type": "boolean",
"default": true
}
}
},
"Color": {
"type": "object",
"description": "Preferred color",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"default": "WOOD",
"enum": [
"BLUE",
"WOOD",
"GREEN"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
},
"Furniture Type": {
"type": "object",
"description": "Kind of Furniture",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"default": "CHAIR",
"enum": [
"LAMP",
"TABLE",
"CHAIR"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
}
},
"required": [
"IDNumber",
"Color",
"Furniture Type"
],
"anyOf": [
{
"properties": {
"Furniture Type": {
"value": {
"const": "LAMP"
}
},
"Function": {
"type": "object",
"description": "Lighting arrangement",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"LIGHT ON",
"LIGHT OFF"
]
}
}
}
},
"required": [
"Furniture Type",
"Function"
]
},
{
"properties": {
"Furniture Type": {
"value": {
"const": "TABLE"
}
},
"Function": {
"type": "object",
"description": "Size of table",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"3' x 4'",
"6' x 4'",
"12' x 4'",
"10' round"
]
}
}
}
},
"required": [
"Furniture Type",
"Function"
]
},
{
"properties": {
"Furniture Type": {
"value": {
"const": "CHAIR"
}
},
"Function": {
"type": "object",
"description": "Planned use",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"WORKSPACE SEAT",
"SPARE SEAT"
]
}
}
},
"Person assigned": {
"type": "object",
"description": "Seating assignment",
"required": [
"value"
],
"properties": {
"value": {
"type": "string"
}
}
}
},
"required": [
"Furniture Type",
"Function",
"Person assigned"
]
}
]
}
}
},
"required": [
"FurnitureData"
]
}
Invalid JSON Example that XMLSpy validates as okay: (it is linked to my schema in the info page) Lamps should not allow 6x4 as a function...
{
"FurnitureData": [
{
"Color": {
"value": "WOOD",
"readOnly": "a",
"custom value": "a"
},
"IDNumber": {
"value": "a",
"readOnly": true
},
"Furniture Type": {
"value": "LAMP",
"custom value": "a"
},
"Function": {
"value": "6' x 4'",
"custom value": "a"
}
}
]
}
Another Invalid example... Chairs have "Person assigned" and the wrong type value is shown but this validates too...
{
"FurnitureData": [
{
"Color": {
"value": "WOOD",
"readOnly": "a",
"custom value": "a"
},
"IDNumber": {
"value": "a",
"readOnly": true
},
"Furniture Type": {
"value": "CHAIR",
"custom value": "a"
},
"Function": {
"value": "6' x 4'",
"custom value": "a"
}
}
]
}
This is following the recommendation in See enum section using anyof
Maybe I must use an if-then construct ? Here, I tried with if-then in the any-of but I also get validations of json that allow enums from the other furniture types...
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Comment describing your JSON Schema",
"type": "object",
"properties": {
"FurnitureData": {
"type": "array",
"items": {
"type": "object",
"properties": {
"IDNumber": {
"type": "object",
"description": "Unique identifier",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"maxLength": 16
},
"readOnly": {
"type": "boolean",
"default": true
}
}
},
"Color": {
"type": "object",
"description": "Preferred color",
"required": [
"value",
"readOnly"
],
"properties": {
"value": {
"type": "string",
"default": "WOOD",
"enum": [
"BLUE",
"WOOD",
"GREEN"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
},
"Furniture Type": {
"type": "object",
"description": "Kind of Furniture",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"default": "CHAIR",
"enum": [
"LAMP",
"TABLE",
"CHAIR"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
}
},
"required": [
"IDNumber",
"Color",
"Furniture Type"
],
"anyOf": [
{
"if": {
"properties": {
"Furniture Type": {
"value": {
"const": "LAMP"
}
}
}
},
"then": {
"properties": {
"Function": {
"type": "object",
"description": "Lighting arrangement",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"LIGHT ON",
"LIGHT OFF"
]
}
}
}
},
"required": [
"Function"
]
}
},
{
"if": {
"properties": {
"Furniture Type": {
"value": {
"const": "TABLE"
}
}
}
},
"then": {
"properties": {
"Function": {
"type": "object",
"description": "Size of table",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"3' x 4'",
"6' x 4'",
"12' x 4'",
"10' round"
]
}
}
}
},
"required": [
"Function"
]
}
},
{
"if": {
"properties": {
"Furniture Type": {
"value": {
"const": "CHAIR"
}
}
}
},
"then": {
"properties": {
"Function": {
"type": "object",
"description": "Planned use",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"WORKSPACE SEAT",
"SPARE SEAT"
]
}
}
},
"Person assigned": {
"type": "object",
"description": "Seating assignment",
"required": [
"value"
],
"properties": {
"value": {
"type": "string"
}
}
}
},
"required": [
"Function",
"Person assigned"
]
}
}
]
}
}
},
"required": [
"FurnitureData"
]
}
The values of a JSON Schema properties
object are subschemas (JSON Schemas in their own right).
Knowing that, if you take your subschema at properties.FurnitureData.anyOf[1].properties['Furniture Type']
, and you take that as a schema... it actually doesn't express any constraints.
The subschema at that location from your schema is...
{
"value": {
"const": "TABLE"
}
}
whereas it needs to be...
{
"properties":{
"value": {
"const": "TABLE"
}
}
}
The easiest way to debug this sort of issue is test your assumptions.
You assumed that allOf[1]
and allOf[2]
should fail, so replace those subschemas with false
(booleans are valid schemas).
In doing so, you find out the assumption is wrong, and allOf[1]
is valid. Of course you expect the const
to be picked up, and therefore this subschema to fail, but it isn't picked up because you were missing properties
and value
isn't a valid JSON Schema keyword.
You can run these sort of quick tests using https://jsonschema.dev/s/Xt1Yi