I want to express conditional validation of schema that contains cross key conditions. Is there a support for this in JSON schema with the available conditional keywords ( allOf/anyOf/if/then/else)
JSON Schema :
{
"type": "object",
"additionalProperties": false,
"properties": {
"x": {
"type": "object",
"additionalProperties": false,
"properties": {
"value": {
"type": "string"
}
}
},
"y": {
"type": "object",
"additionalProperties": false,
"properties": {
"key1": {
"type": "string",
"enum": ["a", "b", "c", "d", "e"]
},
"key2": {
"type": "string",
"enum": ["x", "y", "m", "n", "r", "s"]
}
},
"anyOf": [{
"allOf": [{
"if": {
"properties": {
"key1": {
"enum": ["a", "b"]
}
}
},
"then": {
"properties": {
"key2": {
"enum": ["x", "y"]
}
}
}
},
{
"if": {
"x": {
"properties": {
"value": {
"const": "myVal"
}
}
}
},
"then": {
"properties": {
"key2": {
"enum": ["x", "y"]
}
}
}
}
]
},
{
"if": {
"properties": {
"key1": {
"enum": ["c", "d"]
}
}
},
"then": {
"properties": {
"key2": {
"type": "string",
"enum": ["m", "n"]
}
}
}
}
]
}
}
}
Sample JSON instance would look like this
{
"x": {
"value": "myVal"
},
"y": {
"key1": "a",
"key2": "x"
}
}
The condition that I want to express is the following 2 conditions
If (x.value == "myVal" AND (y.key1 == "a" OR y.key1 == "b") then y.key2 should only have "x" or "y"
(OR)
If ( y.key1 == "c" OR y.key1 == "d") then y.key2 should contain only "m" or "n".
(OR)
y.key2 can take any of the allowed enum values defined in y.key2 property.
The conditional I have used the JSON Schema doesn't work. I tried validating using https://www.jsonschemavalidator.net/ .
Any help would be deeply appreciated :)
Thanks
So I think this is one of those cases where it's better to forget about the if
/then
/else
keywords and just define the good states in a oneOf
. (I suggest oneOf
instead of anyOf
because exactly one of these states should match.)
So for your schema, you want ONE OF
x.value == "myVal"
y.key1 in ["a", "b"]
y.key2 in ["x", "y"]
y.key1 in ["c", "d"]
y.key2 in ["m", "n"]
x.value == "myVal"
y.key1 in ["a", "b"]
y.key1 in ["c", "d"]
true
(or {}
if you're pre-draft-6)It looks like you have #1 and #2 worked out; just drop the conditional logic. It's the NOT in #3 that does the work. Here we're saying that if the condition for #1 is false and the condition for #2 is false, then any value already defined in the enum for y.key2
is fine.
The reason we have to explicitly express that we don't want the conditions for #1 and #2 is that without them, we just have a true
schema, which allows everything (that's not previously constrained).
Now the other gotcha here is that you have x
being used in one of your conditions, but your anyOf
subschema is under the definition for y
, so it can't see x
at all. To fix this, you'll want to move that subschema to the root, as a sibling to properties
. Here it can view the entire instance, not just the value in the y
property.
Thanks much. Your suggestion worked. . Though I wonder why I couldn't use if/then/else ( trying to reduce the verbosity of the schema)
Working example - jsonschema.dev/s/D3cPd