JSON 架构需要特定的数组元素
JSON Schema require a specific array element
我将属性列表定义为 json 模式:
{
"$schema": "http://json-schema.org/schema#",
"type": "object",
"definitions": {
"attribute": {
"type": "object",
"properties": {
"symbolic-name": { "type":"string"},
"value": { "type":"string"}
},
"required": ["symbolic-name", "value"]
},
"displayname": {
"type": "object",
"properties": {
"symbolic-name": {"enum":["displayName"]},
"value": { "type":"string"}
},
"required": ["symbolic-name", "value"]
}
},
"properties": {
"attributes":{
"type": "array",
// This is the crucial point:
"items": {"oneOf": [
{"$ref": "#/definitions/attribute"},
{"$ref": "#/definitions/displayname"}
]},
"uniqueItems": true
}
}
}
我想要求列表只有一个属性 symbolic-name="displayName"
一个有效的数据对象应该是:
{
"attributes":[
{"symbolic-name": "displayName", "value": "Display Name"},
{"symbolic-name": "somethingElse", "value": "value1"}
{"symbolic-name": "somethingElse", "value": "value2"}
]
}
现在,这无法验证,因为 displayName 属性不仅匹配 "oneOf",而且还匹配两个限制。我无法将其更改为 "allOf",因为那样除 displayName 之外的所有其他属性都将不再匹配。
为了使您的 "oneOf"
正常工作,您的 "attribute" 和 "displayname" 架构需要相互排斥 - 如所写,任何有效的 "displayname"也是有效的 "attribute"。我们可以通过排除 "displayName" 作为 "attribute":
的有效符号名称来做到这一点
"symbolic-name": {
"type": "string",
"not": {"enum": ["displayName"]}
}
现在符号名称为 "displayName" 的元素可以匹配 "displayname" 定义,但永远不会匹配 "attribute" 定义。
你问题的另一部分是关于在你的数组中恰好有一个 "displayname"。这更棘手。它还取决于您使用的 JSON Schema 的草稿。 4 和 6 已实施,7 于周一发布 - 仅声明 "$schema": "http://json-schema.org/schema#"
意味着您使用的是最新的,即 7。我建议使用 $schema
的特定草案而不是非-第一个可能会更改,恕不另行通知。
如果您同意 "displayname" 是数组的 first 元素,那么这在任何草稿中都有效(而且您甚至不需要 "oneOf"
):
"items": [{"$ref": "#/definitions/displayname"}],
"additionalItems": {"$ref": "#/definitions/attribute"}
注意这里的"items"
是一个数组。这意味着第一项必须是 "displayname" 并且超出第一项的所有其他项目必须是 "attribute"s.
如果您想在任何位置允许 "displayname",那就更难了。从 draft-06 开始,有 "contains"
,它至少需要一项来匹配给定的模式。但是没有简单的方法可以说"at most one item"。然而,"minContains"
和 "maxContains"
已被建议用于 draft-08:https://github.com/json-schema-org/json-schema-spec/issues/441
现在,希望您可以接受 "displayname" 要求第一个位置,因为这在所有草稿中都适用。
我将属性列表定义为 json 模式:
{
"$schema": "http://json-schema.org/schema#",
"type": "object",
"definitions": {
"attribute": {
"type": "object",
"properties": {
"symbolic-name": { "type":"string"},
"value": { "type":"string"}
},
"required": ["symbolic-name", "value"]
},
"displayname": {
"type": "object",
"properties": {
"symbolic-name": {"enum":["displayName"]},
"value": { "type":"string"}
},
"required": ["symbolic-name", "value"]
}
},
"properties": {
"attributes":{
"type": "array",
// This is the crucial point:
"items": {"oneOf": [
{"$ref": "#/definitions/attribute"},
{"$ref": "#/definitions/displayname"}
]},
"uniqueItems": true
}
}
}
我想要求列表只有一个属性 symbolic-name="displayName"
一个有效的数据对象应该是:
{
"attributes":[
{"symbolic-name": "displayName", "value": "Display Name"},
{"symbolic-name": "somethingElse", "value": "value1"}
{"symbolic-name": "somethingElse", "value": "value2"}
]
}
现在,这无法验证,因为 displayName 属性不仅匹配 "oneOf",而且还匹配两个限制。我无法将其更改为 "allOf",因为那样除 displayName 之外的所有其他属性都将不再匹配。
为了使您的 "oneOf"
正常工作,您的 "attribute" 和 "displayname" 架构需要相互排斥 - 如所写,任何有效的 "displayname"也是有效的 "attribute"。我们可以通过排除 "displayName" 作为 "attribute":
"symbolic-name": {
"type": "string",
"not": {"enum": ["displayName"]}
}
现在符号名称为 "displayName" 的元素可以匹配 "displayname" 定义,但永远不会匹配 "attribute" 定义。
你问题的另一部分是关于在你的数组中恰好有一个 "displayname"。这更棘手。它还取决于您使用的 JSON Schema 的草稿。 4 和 6 已实施,7 于周一发布 - 仅声明 "$schema": "http://json-schema.org/schema#"
意味着您使用的是最新的,即 7。我建议使用 $schema
的特定草案而不是非-第一个可能会更改,恕不另行通知。
如果您同意 "displayname" 是数组的 first 元素,那么这在任何草稿中都有效(而且您甚至不需要 "oneOf"
):
"items": [{"$ref": "#/definitions/displayname"}],
"additionalItems": {"$ref": "#/definitions/attribute"}
注意这里的"items"
是一个数组。这意味着第一项必须是 "displayname" 并且超出第一项的所有其他项目必须是 "attribute"s.
如果您想在任何位置允许 "displayname",那就更难了。从 draft-06 开始,有 "contains"
,它至少需要一项来匹配给定的模式。但是没有简单的方法可以说"at most one item"。然而,"minContains"
和 "maxContains"
已被建议用于 draft-08:https://github.com/json-schema-org/json-schema-spec/issues/441
现在,希望您可以接受 "displayname" 要求第一个位置,因为这在所有草稿中都适用。