简体   繁体   中英

JSON Schema oneOf for array options

I am trying to model the scenario where the JSON payload has a "steps" array and it's contents may be only one of predefined a set of options, for example:

{ "steps": ["s0"] } 
or
{ "steps": ["s1"] }
or
{ "steps": ["s0", "s2"] }

How would I model this in a schema? The following:

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",

  "title": "Payload",
  "type": "object",

  "properties": {
    "steps": {
      "type": "array",
      "oneOf": [
        ["s0"],
        ["s1"],
        ["s0", "s2"]
      ]
    }
  }
}     

fails with "Unexpected token when reading schemas: StartArray. Path 'properties.steps.oneOf[0]'"

EDIT

Apologies for moving the goalposts, I simplified my problem to a point where the proposed solutions work for the simplified version but not the original. The extra complication is that instead of string values I need to $ref objects sooo...

Sample inputs:

{ "steps": [{"name": "S0"}] } 
or
{ "steps": [{"name": "S1"}] }
or
{ "steps": [{"name": "S1"}, {"name": "S2"}] }

A schema (following suggestion by @EylM) that doesn't match as expected

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Request",
  "type": "object",
  "properties": {
    "steps": {
      "type": "array",
      "oneOf": [
        {
          "const": [
            {"$ref": "#/definitions/s0"}
          ]
        },
        {
          "const": [
            {"$ref": "#/definitions/s1"}
          ]
        },
        {
          "const": [
            {"$ref": "#/definitions/s1"},
            {"$ref": "#/definitions/s2"}
          ]
        }
      ]
    }
  },
  "required": [
    "steps"
  ],
  "definitions": {
    "s0": {
      "type": "object",
      "properties": {"name": { "const": "S0" }}
    },
    "s1": {
      "type": "object",
      "properties": {"name": {"const": "S1" }}
    },
    "s2": {
      "type": "object",
      "properties": {"name": { "const": "S2" }}
      }
    }
}

With this schema and input { "steps":[{"name": "s0"}] } I get JSON is valid against no schemas from 'oneOf'

For whatever it's worth, I am using https://www.jsonschemavalidator.net/ for experimenting.

Try using enum keyword.

The enum keyword is used to restrict a value to a fixed set of values. It must be an array with at least one element, where each element is unique.

json-schema - More info .

In your case, JSON would look like:

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",

  "title": "Payload",
  "type": "object",

  "properties": {
    "steps": {
      "type": "array",
      "oneOf": [
        {"enum": ["s1"]},
        {"enum": ["s0"]},
        {"enum": ["s1, s2"]}
      ]
    }
  }
}  

Updated my answer according to your edit. Following JSON schema validates all 3 conditions in the question and I assumed { "steps": [{"name": "S2"}, {"name": "S1"}] } is not valid. Correct me if I'm wrong.

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Request",
  "type": "object",
  "properties": {
    "steps": {
      "type": "array",
      "anyOf": [
        {
          "maxItems": 1,
          "items": {
            "oneOf": [
              {
                "$ref": "#/definitions/s0"
              },
              {
                "$ref": "#/definitions/s1"
              }
            ]
          }
        },
        {
          "minItems": 2,
          "maxItems": 2,
          "items": [
            {
              "$ref": "#/definitions/s1"
            },
            {
              "$ref": "#/definitions/s2"
            }
          ]
        }
      ]
    }
  },
  "required": [
    "steps"
  ],
  "definitions": {
    "s0": {
      "type": "object",
      "properties": {
        "name": {
          "const": "S0"
        }
      }
    },
    "s1": {
      "type": "object",
      "properties": {
        "name": {
          "const": "S1"
        }
      }
    },
    "s2": {
      "type": "object",
      "properties": {
        "name": {
          "const": "S2"
        }
      }
    }
  }
}

In case you want to pass validation for { "steps": [{"name": "S2"}, {"name": "S1"}] } use another anyOf block as follows.

{
    "minItems": 2,
    "maxItems": 2,
    "items": [
       {
          "$ref": "#/definitions/s2"
       },
       {
          "$ref": "#/definitions/s1"
       }
    ]
}

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