问题
I have seen answers to similar questions that do not quite match this particular case, so apologies if I missed a relevant answer.
I have a heterogeneous array of objects that I would like to validate. These objects have the same format at the top level, but the child objects are quite different and can only be identified by the attributes present in each child.
The problem maps to validating the following data, though I have more than two object types in the array:
{
"heterogeneous_array": [{
"arbitrary_name": "foobar",
"params": {
"aa": "foo",
"ab": "bar"
}
},
{
"arbitrary_name": "barfoo",
"params": {
"ba": "baz",
"bb": "bot"
}
}
]
}
I am using the following schema, which claims to validate the input json even when the objects under the “params” key are invalid. How can I fix the json schema?
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"heterogeneous_array": {
"$ref": "#/definitions/heterogeneous_array"
}
},
"definitions": {
"heterogeneous_array": {
"type": "array",
"items": {
"arbitrary_name": {
"type": "string"
},
"params": {
"oneOf": [{
"$ref": "#/definitions/schema_a"
},
{
"$ref": "#/definitions/schema_b"
}
]
},
"required": ["arbitrary_name", "params"]
}
},
"schema_a": {
"properties": {
"aa": {
"type": "string"
},
"ab": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["aa", "ab"]
},
"schema_b": {
"properties": {
"ba": {
"type": "string"
},
"bb": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["ba", "bb"]
}
}
}
Thank you in advance!
回答1:
The first thing that jumps out at me is that parameters
and arbitrary_name
are not JSON Schema keywords. I think you're missing a few properties
keywords.
Try this:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"heterogeneous_array": {
"$ref": "#/definitions/heterogeneous_array"
}
},
"definitions": {
"heterogeneous_array": {
"type": "array",
"items": {
"properties": { // missing this
"arbitrary_name": {
"type": "string"
},
"params": {
"oneOf": [{
"$ref": "#/definitions/schema_a"
},
{
"$ref": "#/definitions/schema_b"
}
]
}
},
"required": ["arbitrary_name", "params"] // "arbitrary_name" was "name"
}
},
"schema_a": {
"properties": { // was "parameters"
"aa": {
"type": "string"
},
"ab": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["aa", "ab"]
},
"schema_b": {
"properties": { // was "parameters"
"ba": {
"type": "string"
},
"bb": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["ba", "bb"]
}
}
}
There are a few other things in there that I commented.
The last thing (to fix what you have) is minor, should be noted, and is probably supported by your JSON library anyway: boolean values in JSON are always lower-case (e.g. false
not False
). (They're actually defined as explicit tokens.)
What is unclear from your question is whether the foobar
object requires the aa
and ab
parameters while the barfoo
object requires the ba
and bb
parameters. If this is the case, you can do some other things if you're using JSON Schema draft 6 or higher.
Draft 6 defines a const
property that you can use to isolate values for specific properties and enforce subschemas on other portions of the object. Using this, you can create a sort of switch statement.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"heterogeneous_array": {
"$ref": "#/definitions/heterogeneous_array"
}
},
"definitions": {
"heterogeneous_array": {
"type": "array",
"items": {
"oneOf": [
{"$ref": "#/definitions/schema_a"},
{"$ref": "#/definitions/schema_b"}
],
"required": ["arbitrary_name", "params"]
}
},
"schema_a": {
"properties": {
"arbitrary_name": {"const": "foobar"},
"params": {
"properties": {
"aa": {
"type": "string"
},
"ab": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["aa", "ab"]
}
}
},
"schema_b": {
"properties": {
"arbitrary_name": {"const": "barfoo"},
"params": {
"properties": {
"ba": {
"type": "string"
},
"bb": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["ba", "bb"]
}
}
}
}
}
This is a bit of a reorganization and you'll need a schema_?
for each value of arbitrary_name
that you have.
Further to this, if you're using draft 7, you also have the if
/then
/else
keywords, but I don't think that makes this use case any cleaner.
来源:https://stackoverflow.com/questions/55168214/validating-heterogeneous-lists-of-objects-with-jsonschema-and-ref