jsonjsonschema

JSON Schema array with objects and validation based on array object types


JSON I want to validate has an array of objects. Each object has two properties tag and value. I want validate value based on the tag field.

For example:

if tag="collection date" value={SOME_REGEX}
else if tag="geographic location" value={SOME_ENUM}
....
else tag={ANY_STRING} value={ANY_STRING}

I have tried few differnt versions with contains and if then. But following is the one I think should work.

Using if then and allOf keywords: Here instead of matching with one if condition, it matchs with all. I have included tag as a required attribute to avoid matching with empty schema, but validation still matchs with all objects.

(online link with errors)

Data

{
  "alias": "lodBeiA",
  "attributes": [
    {
      "tag": "collection date",
      "value": "2021"
    },
    {
      "tag": "geographic location",
      "value": "UK"
    },
    {
      "tag": "strain",
      "value": "CBS 14171"
    }
  ]
}

Schema I tried:

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "type": "object",
  "properties": {
    "alias": {
      "type": "string"
    },
    "attributes": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "tag": {
            "type": "string"
          },
          "value": {
            "allOf": [
              {
                "if": {
                  "properties": {
                    "tag": {
                      "enum": [
                        "collection date"
                      ]
                    }
                  },
                  "required": [
                    "tag"
                  ]
                },
                "then": {
                  "type": "string",
                  "pattern": "(^[12][0-9]{3}(-(0[1-9]|1[0-2])(-(0[1-9]|[12][0-9]|3[01])(T[0-9]{2}:[0-9]{2}(:[0-9]{2})?Z?([+-][0-9]{1,2})?)?)?)?(/[0-9]{4}(-[0-9]{2}(-[0-9]{2}(T[0-9]{2}:[0-9]{2}(:[0-9]{2})?Z?([+-][0-9]{1,2})?)?)?)?)?$)"
                }
              },
              {
                "if": {
                  "properties": {
                    "tag": {
                      "enum": [
                        "geographic location"
                      ]
                    }
                  },
                  "required": [
                    "tag"
                  ]
                },
                "then": {
                  "enum": [
                    "UK",
                    "UGANDA"
                  ]
                }
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "required": [
          "tag",
          "value"
        ]
      }
    }
  },
  "additionalProperties": false,
  "required": [
    "alias",
    "attributes"
  ]
}

Solution

  • if, then should be applied at the parent of the properties you want to validate, not the properties level.

    I also updated your constraint for additionalProperties to use the draft-2019-09 keyword, unevaluatedProperties

    {
      "$schema": "https://json-schema.org/draft/2019-09/schema",
      "type": "object",
      "properties": {
        "alias": {
          "type": "string"
        },
        "attributes": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "tag": {
                "type": "string"
              },
              "value": {
                "type": "string"
              }
            },
            "required": [
              "tag",
              "value"
            ],
            "allOf": [
              {
                "if": {
                  "properties": {
                    "tag": {
                      "enum": [
                        "collection date"
                      ]
                    }
                  },
                  "required": [
                    "tag"
                  ]
                },
                "then": {
                  "properties": {
                    "value": {
                      "type": "string",
                      "pattern": "(^[12][0-9]{3}(-(0[1-9]|1[0-2])(-(0[1-9]|[12][0-9]|3[01])(T[0-9]{2}:[0-9]{2}(:[0-9]{2})?Z?([+-][0-9]{1,2})?)?)?)?(/[0-9]{4}(-[0-9]{2}(-[0-9]{2}(T[0-9]{2}:[0-9]{2}(:[0-9]{2})?Z?([+-][0-9]{1,2})?)?)?)?)?$)"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "tag": {
                      "enum": [
                        "geographic location"
                      ]
                    }
                  },
                  "required": [
                    "tag"
                  ]
                },
                "then": {
                  "properties": {
                    "value": {
                      "enum": [
                        "UK",
                        "UGANDA"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "unevaluatedProperties": false,
      "required": [
        "alias",
        "attributes"
      ]
    }