简体   繁体   中英

JSON Schema Nested If Then

I cannot seem to find a working way of applying multiple if/then logic on an enum.

anyOf doesnt apply the conditional logic, but instead it says if any of them match then thats good.

allOf again doesnt apply the conditional logic but tests a superset of the properties/required fields.

Here is a JSON Schema example:

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "required": [
    "type"
  ],
  "properties": {
    "type": {
      "$id": "#/properties/type",
      "enum": [
        "a",
        "b",
        "c"
      ],
      "title": "The Type"
    },
    "options": {
      "$id": "#/properties/options",
      "type": "object",
      "title": "The Options Schema",
      "oneOf": [
        {
          "if": { "properties": { "type": { "const": "a" } }
          },
          "then": {
            "required": [ "option1" ],
            "properties": {
              "option1": {
                "$id": "#/properties/options/properties/option1",
                "type": "boolean",
                "title": "The option1 Schema"
              }
            }
          }
        },
        {
          "if": { "properties": { "type": { "const": "b" } }
          },
          "then": {
            "required": [ "option2" ],
            "properties": {
              "option2": {
                "$id": "#/properties/options/properties/option2",
                "type": "boolean",
                "title": "The option2 Schema"
              }
            }
          }
        },
        {
          "if": { "properties": { "type": { "const": "c" } }
          },
          "then": {
            "required": [],
            "properties": {}
          }
        }
      ]
    }
  }
}

If you validate against this JSON:

{
  "type": "a",
  "options": {
    "option1": true
  }
}

It fails because option2 is required.

If you change it to anyOf then it succeeds, but if you change the JSON to be invalid:

{
  "type": "a",
  "options": {
    "option2": false
  }
}

It still succeeds.

I havent managed to get nested if/then/else/if/then/else working either.

How can i perform a check where I have set of properties for each type and you cannot intermingle them? Is this actually possible, or should I just change my design.

First, you can test your schemas here . There are several of these sites across the internet.

Second, the if / then / else construct was introduced to replace a oneOf for these kind of enum scenarios, not be combined with it.

This subschema

"if": { "properties": { "type": { "const": "a" } } },
"then": {
  "required": [ "option1" ],
  "properties": {
    "option1": {
      "$id": "#/properties/options/properties/option1",
      "type": "boolean",
      "title": "The option1 Schema"
    }
  }
}

doesn't actually fail when type is not a . It merely says that if type=a , apply the then subschema. It doesn't say anything about what do validate if type is not a , so it passes. If you add an else:false to this, it'll be more in line with what you're thinking, but I encourage you to think about it differently.

Use oneOf or if / then / else , but not both. I suggest changing your subschemas to use this format:

{
  "properties": {
    "type": { "const": "a" },
    "option1": {
      "$id": "#/properties/options/properties/option1",
      "type": "boolean",
      "title": "The option1 Schema"
    }
  },
  "required": [ "option1" ],
}

This asserts that option1 is required and must be a boolean, and that type=a . If type is not a , this schema fails, which is what you want.

This answer describes what you need to do in a bit more detail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM