使用 JsonSchema 和 $ref 验证异构对象列表

Validating Heterogeneous Lists of Objects with JsonSchema and $ref

我看到了类似问题的答案not quite match this particular case,如果我错过了相关答案,我深表歉意。

我有一个异构的对象数组需要验证。这些对象在顶层具有相同的格式,但子对象却大不相同,只能通过每个子对象中存在的属性来识别。

问题映射到验证以下数据,尽管我在数组中有两个以上的对象类型:

{
  "heterogeneous_array": [{
      "arbitrary_name": "foobar",
      "params": {
        "aa": "foo",
        "ab": "bar"
      }
    },
    {
      "arbitrary_name": "barfoo",
      "params": {
        "ba": "baz",
        "bb": "bot"
      }
    }
  ]
}

我正在使用以下模式,它声称即使在“params”键下的对象无效时也能验证输入json。如何修复 json 模式?

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "arbitrary_name": {
          "type": "string"
        },
        "params": {
          "oneOf": [{
              "$ref": "#/definitions/schema_a"
            },
            {
              "$ref": "#/definitions/schema_b"
            }
          ]
        },
        "required": ["arbitrary_name", "params"]
      }
    },
    "schema_a": {
      "properties": {
        "aa": {
          "type": "string"
        },
        "ab": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["aa", "ab"]
    },
    "schema_b": {
      "properties": {
        "ba": {
          "type": "string"
        },
        "bb": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["ba", "bb"]
    }
  }
}

提前致谢!

我首先想到的是 parametersarbitrary_name 不是 JSON 架构关键字。我认为您缺少一些 properties 个关键字。

试试这个:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "properties": {             // missing this
          "arbitrary_name": {
            "type": "string"
          },
          "params": {
            "oneOf": [{
                "$ref": "#/definitions/schema_a"
              },
              {
                "$ref": "#/definitions/schema_b"
              }
            ]
          }
        },
        "required": ["arbitrary_name", "params"]    // "arbitrary_name" was "name"
      }
    },
    "schema_a": {
      "properties": {             // was "parameters"
        "aa": {
          "type": "string"
        },
        "ab": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["aa", "ab"]
    },
    "schema_b": {
      "properties": {             // was "parameters"
        "ba": {
          "type": "string"
        },
        "bb": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["ba", "bb"]
    }
  }
}

我评论了一些其他内容。

最后一件事(修复你所拥有的)是次要的,应该注意,并且可能无论如何都被你的 JSON 库支持:JSON 中的布尔值总是小写的(例如 false 而不是 False)。 (它们实际上被定义为显式标记。)


您的问题中不清楚的是 foobar 对象是否需要 aaab 参数,而 barfoo 对象是否需要 babb 参数。在这种情况下,如果您使用的是 JSON Schema draft 6 或更高版本,则可以做一些其他事情。

草案 6 定义了一个 const 属性,您可以使用它来隔离特定属性的值并在对象的其他部分强制执行子模式。使用它,您可以创建一种 switch 语句。

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "oneOf": [
          {"$ref": "#/definitions/schema_a"},
          {"$ref": "#/definitions/schema_b"}
        ],
        "required": ["arbitrary_name", "params"]
      }
    },
    "schema_a": {
      "properties": {
        "arbitrary_name": {"const": "foobar"},
        "params": {
          "properties": {
            "aa": {
              "type": "string"
            },
            "ab": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": ["aa", "ab"]
        }
      }
    },
    "schema_b": {
      "properties": {
        "arbitrary_name": {"const": "barfoo"},
        "params": {
          "properties": {
            "ba": {
              "type": "string"
            },
            "bb": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": ["ba", "bb"]
        }
      }
    }
  }
}

这有点重组,您需要为您拥有的每个 arbitrary_name 值分配一个 schema_?

除此之外,如果您使用的是草案 7,您还可以使用 if/then/else 关键字,但我认为这不会产生这种用途任何清洁工。