根据 JSON 架构中的其他 属性 值设置其他属性

Setting additional properties based on other property values in JSON schema

我想根据现有 属性 的值设置筛选项的一些属性。如果 属性 Type 的值为 Range,则应将属性 FromTo 添加到 filterItem。否则其余的属性应该是 FilterValues 的数组。我尝试使用 if 和 else 设置属性,但似乎缺少某些东西。

我的 JSON 架构的部分:

"Filter": {
              "type": [
                "array",
                "null"
              ],
              "items": {
                "$ref": "#/definitions/filterItem"
              },
              "additionalProperties": false
            }
___________________________________________________

"filterItem": {
      "type": "object",
      "properties": {
        "AttributeCode": {
          "type": "string",
          "pattern": "^[a-z0-9_-]+$"
        },
        "Typ": {
          "type": "string"
        },
        "if": {
          "properties": {
            "Typ": {
              "const": "Range"
            }
          }
        },
        "then": {
          "properties": {
            "From": {
              "type": "integer",
              "minLength": 1
            },
            "To": {
              "type": "integer",
              "minLength": 1
            }
          },
          "additionalProperties": false
        },
        "else": {
          "properties": {
            "FilterValues": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^[a-z0-9_-]+$"
              }
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    }

验证器显示属性不符合我的架构(屏幕截图): validator

您的架构存在两个主要问题,您如何使用 if-then-else 以及如何使用 addtionalProperties.

if-then-else

JSON 架构关键字只能出现在架构上下文中。 properties 定义一个对象,其值为模式。 properties 本身不是架构。

"properties": {
  "foo": { ... }
  "if": { ... },
  "then": { ... }
}

这没有定义 属性、"foo" 加上条件。它定义了三个属性:"foo"、"if"、"then"。您需要将条件提高一个级别才能被验证器识别。

"properties": {
  "foo": { ... }
},
"if": { ... }
"then": { ... }

否则,您正在正确使用 if-then-else。只是放错地方了。

additionalProperties

一旦您将 if-then-else 放在正确的位置,您会发现出现了一堆 additionalProperties 错误。 additionalProperties 只能考虑架构中同一位置的 propertiespatternProperties 关键字。

{
  "allOf": [
    {
      "properties": {
        "foo": { ... }
      }
    },
    {
      "properties": {
        "bar": { ... }
      },
      "additionalProperties": false
    }
  ]
}

/allOf/1/additionalProperties只能兼顾/allOf/1/properties,不能兼顾/allOf/0/properties。因此,{ "foo": 1, "bar": 2 } 将无效,因为 "foo" 未在 /allOf/1/properties.

中定义

有几种方法可以解决这个问题。首选方法是不使用 additionalProperties。忽略其他属性而不是禁止它们。这最适合可演化的模式,但根据领域的不同,它并不总是可行的。

要有效地使用 additionalProperties,您需要在同一个 properties 关键字下使用所有可能的 属性 名称。

"properties": {
  "foo": { ... },
  "bar": { ... }
},
"required": ["foo"],
"additionalProperties": false,
"if": {
  "properties": {
    "foo": { "const": 1 }
  },
  "required": ["foo"]
},
"then": { "required": ["bar"] }

这是一种可能的方法。 "bar" 仅在 "foo" 为 1 时才需要,但 "bar" 定义在顶部并且仅在条件通过时才需要。这不仅使 additionalProperties 像您预期的那样工作,而且更易于阅读,因为所有 属性 定义都在一个地方并且条件模式最少。

此时您可能担心当 "foo" 不是 1 时包含 "bar" 不会引发错误。同样,如果您的域允许,我鼓励您忽略额外的 属性 而不是禁止它。但是,如果你真的需要,你可以使用 else 来禁止额外的字段。

"else": { "not": { "required": ["bar"] } }

注意不要被该架构中的单词混淆。这并不意味着 "not required" 听起来像 "optional",而是 "forbidden".