Search code examples
json.netjsonschema

JSON Schema - Child type dependant on parent element name (with Json.Net)


Having following JSON schema:

{
  "type": "object",
  "properties": {
    "SomeForms": {
      "additionalProperties": false,
      "properties": {
        "Forms": {
          "type": "object",
          "additionalProperties": false,
          "patternProperties": {
            "^(TestTestForm1|TestForm2)$": {
              "type": "object",
              "properties": {
                "Options": {
                  "type": "object",
                  "additionalProperties": false,
                  "patternProperties": {
                    "^(ExampleDropdown|ExampleCheckboxes)$": {
                      "type": "object",
                      "properties": {
                        "DefaultValue": {
                          "type": "string"
}}}}}}}}}}}}}

And following test JSON:

{
  "SomeForms": {
    "Forms": {
      "TestTestForm1": {
        "Options": {
          "ExampleDropdown": {
            "DefaultValue": "Dropdown"
}}}}}}

How I can make the DefaultValue have different type, depending on the parent "^(TestTestForm1|TestForm2)$"?
Example:
- if the parent is TestTestForm1, I want DefaultValue to be number
- if the parent is TestTestForm1, I want DefaultValue to be string

I am using Json.NET library to generate schemas, so the C# example would be best, but having JSON schema example would also be a clue for me.

Thanks in advance.

I tried:

"Forms": {
    "allOf": [
    { 
            "if": { "patternProperties": { "const": "TestTestForm1" } }, 
            "then": { "patternProperties" : { "TestTestForm1": { "properties": { "Options": { "patternProperties": { "properties": { "DefaultValue": { "type": "number" } } } } } } } } }
],

But I does not work. Main thing I don't know, is how to make "if" check on the parent name, not the value (above I am using "const", which I guess is correct only for checking the "value" of property, not it's name).


Solution

  • You can't "look up" the schema tree in JSON Schema. So you need to put the condition the level of the Forms object as you did. But this results in a quite verbose solution like this:

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "description": "JSON schema generated with JSONBuddy https://www.json-buddy.com",
      "type": "object",
      "properties": {
        "SomeForms": {
          "additionalProperties": false,
          "properties": {
            "Forms": {
              "type": "object",
              "additionalProperties": false,
              "patternProperties": {
                "^(TestTestForm1|TestForm2)$": {
                  "type": "object",
                  "properties": {
                    "foo": { },
                    "bar": { }
                  }
                }
              },
              "allOf": [
                {
                  "if": {
                    "properties": { "TestTestForm1": true }
                  },
                  "then": {
                    "properties": {
                      "TestTestForm1": {
                        "type": "object",
                        "properties": {
                          "Options": {
                            "type": "object",
                            "patternProperties": {
                              "^(ExampleDropdown|ExampleCheckboxes)$": {
                                "type": "object",
                                "properties": {
                                  "DefaultValue": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                {
                  "if": {
                    "properties": { "TestForm2": true }
                  },
                  "then": {
                    "properties": {
                      "TestForm2": {
                        "type": "object",
                        "properties": {
                          "Options": {
                            "type": "object",
                            "patternProperties": {
                              "^(ExampleDropdown|ExampleCheckboxes)$": {
                                "type": "object",
                                "properties": {
                                  "DefaultValue": {
                                    "type": "number"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
    

    I added empty definitions for "foo" and "bar" keys at the place where you could add parts of the schema which are in common.

    I can't think of any shorter version to solve this.