Json schema permits override of fields in objects in array

Viewed 477

I have an json that looks like this

  "List": {
     {"Color": "red"},
     {}
  },
  "Color": "grey"
}

whereas it means that the default color is grey, and the object in the list could override this Color. The schema should allow the json to pass as long as default color(the property in the same level of List) is present. If not, it shall only allow the json to pass the schema check if all items in the list have specified a "Color".

May I know how can I write a json schema that does this check? I am aware of anyOf but I don't think it can check for all items in the array.

I tried

{
  "type": "object",
  "properties": {
    "List": {"type": "array", "items": {"$ref:" "#/definitions/Item"}},
    "Color": {"type": "string"}
  },
  "definitions": {
    "Item": {"type: "object", "properties": " {"Color": {"type": "string"}}}
  },
  "anyOf": {
  {
    "type": "object",
      "required": ["Color"]  
  },
  {
    "type": "object",
    "List": {
      "type": "array",
      "items": {"$ref": "#/definitions/Item", "required": ["Color"]}
    }
  }
}

But it does not seem that the required color for the anyOf[1] is picked up by the validator. Please help.! Thank you.

2 Answers

The schema in the other answer is correct, but is unnecessarily complicated. Here's an example that removes duplication and make the schema easier to read.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "List": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "Color": { "type": "string" },
          "Shape": { "type": "string" }
        }
      }  
    },
    "Color": { "type": "string" },
    "Shape": { "type": "string" }
  },
  "required": ["List"],
  "allOf": [
    { "$ref": "#/definitions/color-required-if-no-default-color" },
    { "$ref": "#/definitions/shape-required-if-no-default-shape" }
  ],
  "definitions": {
    "color-required-if-no-default-color": {
      "anyOf": [
        { "required": ["Color"] },
        {
          "properties": {
            "List": {
              "items": { "required": ["Color"] }
            }
          }
        }
      ]
    },
    "shape-required-if-no-default-shape": {
      "anyOf": [
        { "required": ["Shape"] },
        {
          "properties": {
            "List": {
              "items": { "required": ["Shape"] }
            }
          }
        }
      ]
    }
  }
}

I think I found out a way:

Schema is like below

{

    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {"Color": {"type":"string"}, "Shape": {"type": "string"}},
    "allOf":[
      {
      "anyOf": [
      {
      "required": ["Color"],
      "properties": {"List": {"type": "array", "items": {"$ref": "#/definitions/Item"}}}
      },
      {
       "properties": {"List": {"type": "array", "items": {"$ref": "#/definitions/ColorItem"}}}
      }
      ]
      },
      {
      "anyOf": [
      {
      "required": ["Shape"],
      "properties": {"List": {"type": "array", "items": {"$ref": "#/definitions/Item"}}}
      },
      {
       "properties": {"List": {"type": "array", "items": {"$ref": "#/definitions/ShapeItem"}}}
      }
      ]
      }
    ],
   "required": ["List"],
   "definitions": {
   "Item": {
       "type": "object",
        "properties": {}
      },
   "ColorItem": {
       "allOf": [{"$ref": "#/definitions/Item"},
                 {"properties": {"Color": {"type": "string"}}, "required": ["Color"]}] 
   },
     "ShapeItem": {
       "allOf": [{"$ref": "#/definitions/Item"},
                 {"properties": {"Shape": {"type": "string"}}, "required": ["Shape"]}] 
   }
  }
}

Basically this does what I want. So it will pass the json only if either there is a Color/Shape read from top-level json, or we can find it in the array.

Related