JSON模式-数组/列表验证可以与anyOf组合使用吗



我有一个json文档,我正在尝试使用以下表单进行验证:

...
"products": [{
"prop1": "foo",
"prop2": "bar"
}, {
"prop3": "hello",
"prop4": "world"
},
...

一个物体可能有多种不同的形式。我的模式如下:

...
"definitions": {
"products": {
"type": "array",
"items": { "$ref": "#/definitions/Product" },
"Product": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/Product_Type1" },
{ "$ref": "#/definitions/Product_Type2" }, 
...
]
},
"Product_Type1": {
"type": "object",
"properties": {
"prop1": { "type": "string" },
"prop2": { "type": "string" }
},
"Product_Type2": {
"type": "object",
"properties": {
"prop3": { "type": "string" },
"prop4": { "type": "string" }
}
...

除此之外,可以通过进一步使用anyOfoneOf来间接地影响各个产品阵列对象的某些属性。

我在使用内置模式验证的VSCode中遇到了问题,它会为products数组中与Product_Type1不匹配的每个项抛出错误。

因此,验证器似乎锁定了它找到的第一个oneOf,不会针对任何其他类型进行验证。

我在jsonschema.org上没有发现oneOf机制的任何限制。这里也没有提到它在专门处理数组的页面中使用:https://json-schema.org/understanding-json-schema/reference/array.html

我尝试的是可能的吗

您的通用方法很好。让我们举一个稍微简单一点的例子来说明出了什么问题。

给定此模式

{
"oneOf": [
{ "properties": { "foo": { "type": "integer" } } },
{ "properties": { "bar": { "type": "integer" } } }
]
}

这个例子

{ "foo": 42 }

乍一看,它与/oneOf/0匹配,而与oneOf/1不匹配。它实际上匹配两个模式,这违反了oneOfoneOf所施加的唯一约束。

请记住,JSON模式中的每个关键字都是一个约束。任何未被架构明确排除的内容都是允许的。/oneOf/1模式中没有任何内容表明不允许使用"foo"属性。也没有说"foo"是必需的。它只是说,如果实例有一个关键字"foo",那么它必须是一个整数。

要解决此问题,您需要required,也可能需要additionalProperties,具体取决于情况。我在这里展示了如何使用additionalProperties,但我建议您不要使用它,除非您需要,因为它确实有一些有问题的属性。

{
"oneOf": [
{
"properties": { "foo": { "type": "integer" } },
"required": ["foo"],
"additionalProperties": false
},
{
"properties": { "bar": { "type": "integer" } },
"required": ["bar"],
"additionalProperties": false
}
]
}