在 JSON 模式的 anyOf 中嵌套 oneOf

use*_*984 4 jsonschema ajv

以下是 JSON 架构和下面链接中提供的 JSON,用于说明目的。

JSON 架构和 JSON

格式:数组中的单个 JSON 对象(及其附加属性,可能会因数组中的其他对象而异)可以属于任意 3 个区域:“美洲”、“亚洲”和“欧洲”,并且至少在区域类型上对象应该在那里。这可以通过数组 minItems 属性来实现)

问题陈述:

  1. 数组中的单个 JSON 对象可以属于任意 3 个区域:“美国”、“亚洲”和“欧洲”,并且至少应该存在区域对象的类型

    ==> 我可以通过将所有区域对象放入 anyOf 数组中来解决此问题,因为我想匹配至少一个有效区域对象。

  2. JSON 对象“亚洲”或“欧洲”可以与其他区域类型一起存在。两者不能共存。

    ==> 我尝试使用“oneOf”,但它通过了 ajv 验证。其实应该会失败。任何人都可以帮忙。谢谢

JSON 模式

{
    "type": "object",
    "properties": {
        "stat_data": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "object",
                "properties": {},
                "anyOf": [{
                        "required": ["region"],
                        "properties": {
                            "region": {
                                "enum": ["america"]
                            },
                            "country": {
                                "type": "string"
                            },
                            "population": {
                                "type": "string"
                            }
                        }
                    },
                    {
                        "oneOf": [
                            {
                                "required": ["region"],
                                "properties": {
                                    "region": {
                                        "enum": ["asia"]
                                    },
                                    "country": {
                                        "type": "string"
                                    },
                                    "details": {
                                        "type": "object",
                                        "properties": {
                                            "language": {
                                                "type": "string"
                                            },
                                            "tz": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                }
                            }, {
                                "required": ["region"],
                                "properties": {
                                    "region": {
                                        "enum": ["europe"]
                                    },
                                    "country": {
                                        "type": "string"
                                    },
                                    "language": {
                                        "type": "string"
                                    }
                                }
                            }
                        ]
                    }
                ]
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

JSON 对象失败,因为“亚洲”和“欧洲”类型对象不能共存。

{
    "stat_data": [{
            "region": "america",
            "country": "USA",
            "states": "50"
        }, {
            "region": "asia",
            "country": "Japan",
            "details": {
                "language": "Japanese",
                "tz": "utc+9.00"
            }
        }, {
            "region": "europe",
            "country": "finland",
            "language": "Finnish"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

JSON 对象作为仅存在的“asia”类型对象而传递。

{
    "stat_data": [{
            "region": "america",
            "country": "USA",
            "states": "50"
        }, {
            "region": "asia",
            "country": "Japan",
            "details": {
                "language": "Japanese",
                "tz": "utc+9.00"
            }
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

JSON 对象作为仅存在的“欧洲”类型对象而传递。

{
    "stat_data": [{
            "region": "america",
            "country": "USA",
            "states": "50"
        }, {
            "region": "europe",
            "country": "finland",
            "language": "Finnish"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

Rel*_*ual 5

我可以理解为什么您尝试了您所做的方法,但是它不能按预期工作,因为您已经定义了数组中的每个项目可能是americaor ( europeor asia),这不是您想要的。

请记住,items将值模式应用于数组中的每个元素。它对整个数组本身没有任何限制。contains检查数组中的至少一项是否根据其值模式进行验证。

你想说的是,数组中的每个项目都可以有americaeuropeasia,但europe如果数组包含,则数组可能不包含asia, 以及相反的。

我重构了架构并做了一些更改。

oneOf希望您也能看到>>(containsnot> )的使用意图很明确contains

JSON Schema 通过添加约束来工作。通常不能通过省略来定义约束。

JSON 模式和数据验证演示

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "containtsAsia": {
      "contains": {
        "properties": {
          "region": {
            "const": "asia"
          }
        }
      }
    },
    "containsEurope": {
      "contains": {
        "properties": {
          "region": {
            "const": "europe"
          }
        }
      }
    }
  },
  "type": "object",
  "properties": {
    "stat_data": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "properties": {
          "region": {
            "enum": [
              "america",
              "asia",
              "europe"
            ]
          },
          "country": {
            "type": "string"
          },
          "population": {
            "type": "string"
          }
        }
      },
      "oneOf": [
        {
          "allOf": [
            {
              "$ref": "#/definitions/containtsAsia"
            },
            {
              "not": {
                "$ref": "#/definitions/containsEurope"
              }
            }
          ]
        },
        {
          "allOf": [
            {
              "$ref": "#/definitions/containsEurope"
            },
            {
              "not": {
                "$ref": "#/definitions/containtsAsia"
              }
            }
          ]
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)