jsonschema

Forbidding Properties in Dependent JSON Schemas


I have the following JSON Schema:

{
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "abc": {
            "type": "string"
        },
        "abc@mandatory": {
            "type": "string"
        },
        "abc@optional": {
            "type": "string"
        },
        "def": {
            "type": "string"
        },
        "def@mandatory": {
            "type": "string"
        },
        "def@optional": {
            "type": "string"
        }
    },
    "dependentSchemas": {
        "abc": {
            "required": [
                "abc@mandatory"
            ]
        },
        "def": {
            "required": [
                "def@mandatory"
            ]
        }
    }
}

It enforces that the property abc@mandatory is present if abc is present. But I want an additional rule saying that neither abc@mandatory nor abc@optional must be present if abc is not present. How can I achieve this?

I generate the JSON schema, and actually there is an arbitrary number of such combinations, for example def and def@....

Background: I want to transform my data into this XML string:

<abc mandatory="foo" optional="bar">Some value</xyz>

The properties containing an @ translate to XML attributes. The attribute mandatory is a mandatory attribute of abc and the attribute optional is an optional attribute of abc.

However, the element abc itself is optional and if it is not present, then neither the attribute mandatory nor optional makes sense.

I am missing two features in JSON Schema: First, I want to define rules for the case that a certain property is not present. Second, I want to find a way to forbid certain properties. I could achieve the second feature by specifying rules that never evaluate to true (for example { "minLength": 1, "maxLength": 0 }) but that would lead to confusing error messages.

If you think that you have an answer to the question, please make sure that the following conditions are met:

Valid data:

{}
{
    "abc": "exists",
    "abc@mandatory": "exists"
}
{
    "def": "exists",
    "def@mandatory": "exists"
}
{
    "abc": "exists",
    "abc@mandatory": "exists",
    "def": "exists",
    "def@mandatory": "exists"
}

Invalid data:

{
    "abc@mandatory": "exists"
}
{
    "abc@optional": "exists"
}
{
    "abc@mandatory": "exists",
    "def": "exists",
    "def@mandatory": "exists"
}

... and so on.

Of course, it is possible to provide a schema by enumerating all valid combinations with allOf, anyOf, and required. But that will blow up the schema when more elements ghi, jk, ... with their corresponding attributes are added. I prefer a solution, where I can add one single group of conditions for every element and its attributes.


Solution

  • You can use dependentRequired and list all the possibilities.

    edit: This is only valid for JSON Schema 2019-09 or newer

    {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "abc": {
          "type": "string"
        },
        "abc@mandatory": {
          "type": "string"
        },
        "abc@optional": {
          "type": "string"
        },
        "def": {
          "type": "string"
        },
        "def@mandatory": {
          "type": "string"
        },
        "def@optional": {
          "type": "string"
        }
      },
      "dependentRequired": {
        "abc": [
          "abc@mandatory"
        ],
        "def": [
          "def@mandatory"
        ],
        "abc@mandatory": [
          "abc"
        ],
        "abc@optional": [
          "abc"
        ]
      }
    }