Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
837 views
in Technique[技术] by (71.8m points)

jsonschema - Json Schema Polymorphism Validate with anyOf

I've got a Pet object that could be either a dog or a cat Depending on what noise they make I'd like to then be able to validate other fields. schema:

{
  "$id": "http://example.com",
  "definitions": {
    "pet": {
      "type": "object",
      "properties": {
        "noise": {
          "enum": [
            "bark",
            "meow"
          ]
        }
      }
    },
    "dog": {
      "$ref": "#/definitions/pet",
      "properties": {
        "noise": {
          "const": "bark"
        },
        "tail": {
          "enum": [
            "short",
            "long"
          ]
        }
      }
    },
    "cat": {
      "$ref": "#/definitions/pet",
      "properties": {
        "noise": {
          "const": "meow"
        },
        "tail": {
          "enum": [
            "wavy",
            "slinky"
          ]
        }
      }
    }
  },
  "type": "object",
  "properties": {
    "pets": {
      "type": "array",
      "items": {
        "anyOf": [
          {
            "$ref": "#/definitions/dog",
            "$ref": "#/definitions/cat"
          }
        ]
      }
    }
  }
}

This works when running the following json through:

{"pets":[{"noise":"meow","tail":"wavy"}]}

but not when running:

{"pets":[{"noise":"bark","tail":"long"}]}
[$.pets[0].tail: does not have a value in the enumeration [wavy, slinky], $.pets[0].noise: must be a constant value meow]

or

{"pets":[{"noise":"bark","tail":"long"},{"noise":"meow","tail":"wavy"}]}
[$.pets[0].tail: does not have a value in the enumeration [wavy, slinky], $.pets[0].noise: must be a constant value meow]

I can get this working by using if/else in the json schema, but requires another type to avoid a circular dependency:

  "petWithConstraints": {
    "$ref":"#/definitions/pet",
    "allOf": [
        {
          "if": {
            "properties": {
              "noise": {
                "const": "bark"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/dog"
          }
        },
        {
          "if": {
            "properties": {
              "noise": {
                "const": "meow"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/cat"
          }
        }
      ]
    }
  }

This means for every new definition it also requires another if statement.

Is there a better method of doing this? (without the extra definition/if statement)

question from:https://stackoverflow.com/questions/65902626/json-schema-polymorphism-validate-with-anyof

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For those that come across this, this was a syntactical error. Each ref should have been in it's own code block.

The corrected part of the schema looks like the following:

"properties": {
    "pets": {
      "type": "array",
      "items": {
        "anyOf": [
          { // Notice each $ref is encapsulated in it's own block
            "$ref": "#/definitions/cat"
          },
          {
            "$ref": "#/definitions/dog"
          }
        ]
      }
    }
  }

Running the following json through gave expected results

{"pets":[{"noise":"bark","tail":"long"},{"noise":"meow","tail":"wavy"}]}
[]
{"pets":[{"noise":"bark","tail":"long"},{"noise":"meow","tail":"wavy"},{"noise":"meow","tail":"slinky"},{"noise":"bark","tail":"short"}]}
[]
{"pets":[{"noise":"bark","tail":"long"},{"noise":"meow","tail":"wavy"},{"noise":"meow","tail":"slinky"},{"noise":"bark","tail":"short"},{"noise":"meow","tail":"short"}]}
[$.pets[4]: should be valid to one and only one of the schemas ]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...