JSON 架构 - 数组/列表验证可以与 anyOf 结合使用吗?

JSON Schema - can array / list validation be combined with 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 数组中不匹配 [=] 的每个项目抛出错误16=].

因此,验证器似乎锁定了它找到的第一个 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。它实际上匹配两个模式,这违反了 oneOf 施加的唯一约束,并且 oneOf 失败。

请记住,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
    }
  ]
}