jsonjsonschemaxmlspy

JSON Schema draft v7 - definition of additional enum properties based on common enum type selection - testing in XMLSpy Pro 2020


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"
    ]
}

Solution

  • 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