如何定义 JSON 模式,其中对象数组至少包含具有预期名称的元素

How to define a JSON schema where an array of objects contains at least the elements with the expected names

我想定义一个 JSON 模式(草案 04),其中对象数组(此处 files)包含 至少 具有定义的 names(此处为 abc)。

  1. 这应该通过:
"files": [
  { "name": "a" },
  { "name": "b" },
  { "name": "c" }
]
  1. 这应该失败(缺少名称为 c 的元素):
"files": [
  { "name": "a" },
  { "name": "b" }
]
  1. 这应该失败(缺少名称为 c 的元素):
"files": [
  { "name": "a" },
  { "name": "b" },
  { "name": "a" }
]
  1. 这应该通过:
"files": [
  { "name": "a" },
  { "name": "b" },
  { "name": "c" },
  { "name": "d" }
]

minItemsuniqueItemsenum 允许我涵盖案例 1、2 和 3,但它不涵盖案例 4,因为它不允许名称 d:

"files": {
  "minItems": 3,
  "uniqueItems": true,
  "items": {
    "properties": {
      "name": {
        "enum": ["a", "b", "c"]
      }
    }
  }
}

编写验证以至少需要名称为 abc 的元素的任何想法,同时还允许 JSON 中具有其他名称的其他项目架构草案 04?

我们先用一些draft-06或更高版本的关键字来看,因为它更容易理解。然后我们将其翻译为 draft-04。

我们可以使用 contains 关键字来断言数组至少包含一个与架构匹配的项目。此示例显示断言数组必须包含具有 属性 “名称”且值为 "a".

的对象
{
  "contains": {
    "type": "object",
    "properties": {
      "name": { "const": "a" }
    },
    "required": ["name"]
  }
}

您可以像这样使用 allOf 组合多个断言来断言“b”和“c”。

{
  "allOf": [
    { "$ref": "#/definitions/contains-a" },
    { "$ref": "#/definitions/contains-b" },
    { "$ref": "#/definitions/contains-c" }
  ]
}

现在我们需要翻译成 draft-04。 const 很简单。

{ "const": "a" }

变成

{ "enum": ["a"] }

contains 的转换远没有那么直观,但它确实有效。我建议将它们放在 definitions 中(如 allOf 示例中所示)以使您的模式更具可读性。

{ "contains": { "$ref": "#/definitions/name-a" } }

变成

{
  "not": {
    "items": {
      "not": { "$ref": "#/definitions/name-a" }
    }
  }
}

完整(详细)解决方案:

"files": {
  "not": {
    "items": {
      "not": {
        "type": "object",
        "properties": {
          "name": { "enum": ["a"] }
        },
        "required": ["name"]
      },
      "not": {
        "type": "object",
        "properties": {
          "name": { "enum": ["b"] }
        },
        "required": ["name"]
      },
      "not": {
        "type": "object",
        "properties": {
          "name": { "enum": ["c"] }
        },
        "required": ["name"]
      }
    }
  }
}