如何根据 JSON 模式中存在的其他属性有条件地禁止属性?
How to conditionally forbid properties based on presence of other properties in JSON Schema?
在我的架构中,我声明了这些属性:
"index_name": {
"type": "string",
"examples": ["foo-wwen-live", "foo"]
},
"locale": {
"type": "string",
"examples": ["wwen", "usen", "frfr"]
},
"environment": {
"type": "string",
"default": "live",
"examples": [
"staging",
"edgengram",
"test"
]
}
我希望根据我的模式验证的 JSON 主体有效 仅当 :
index_name
存在,并且locale
和environment
不存在;
locale
and/or enviroment
存在,index_name
不存在 出席
简而言之,locale
和 environment
绝不能与 index_name
混用。
测试用例和期望的结果:
这些应该通过:
案例#1
{
"locale": "usen"
}
案例 #2
{
"environment": "foo"
}
案例 #3
{
"environment": "foo",
"locale": "usen"
}
案例 #4
{
"index_name": "foo-usen"
}
这些不应该通过:
案例 #5
{
"index_name": "foo-usen",
"locale": "usen"
}
案例 #6
{
"index_name": "foo-usen",
"environment": "foo"
}
案例 #7
{
"index_name": "foo-usen",
"locale": "usen",
"environment": "foo"
}
我为我的架构创建了以下规则,但它并未涵盖所有情况。例如,如果 locale
和 environment
都存在,则如果 index_name
也存在,则验证 returns 失败,根据案例 #7,这是正确的行为。但是,如果 locale
和 environment
中只有一个存在,它允许 index_name
也存在(在案例 #5 和 #6 中失败)。
"oneOf": [
{
"required": ["index_name"],
"not": {"required": ["locale", "environment"]}
},
{
"anyOf": [
{
"required": ["locale"],
"not": {"required": ["index_name"]}
},
{
"required": ["environment"],
"not": {"required": ["index_name"]}
}
]
}
]
关于 "not": {"required": []}
声明如何工作,我得到的信息很复杂。 claim this means that it forbids anything declared in the array to be present, in contrary to what idea does the syntax give. Other claim 这应该完全按照听起来的方式来理解:数组中列出的属性 不需要 - 它们可以存在,但如果它们不存在也没关系.
除此规则外,我还要求在所有情况下都存在一个不相关的 属性,并且我设置了 "additionalProperties": false
。
满足我所有测试用例的规则是什么?
因为 required: [a, b]
意味着(a 必须存在且 b 必须存在)
然后 not: {required: [a, b]}
表示(不(a 必须存在且 b 必须存在))
这在逻辑上等同于(a 不得存在或 b 不得存在)。
所以这不是正确的表达方式(a 不得存在且 b 不得存在)。你需要两个 not
s.
根据您的要求,这是正确的表达方式:
{
"oneOf": [
{
"required": ["index_name"],
"allOf": [
{"not": {"required": ["locale"]}},
{"not": {"required": ["environment"]}}
]
},
{
"anyOf": [
{"required": ["locale"]},
{"required": ["environment"]}
],
"not": {
"required": ["index_name"]
}
}
]
}
依赖关系
这是 dependencies
关键字的工作。下面说
- 如果 "locale" 存在,则 "index_name" 被禁止。
- 如果 "environment" 存在,则 "index_name" 被禁止。
|
"dependencies": {
"locale": { "not": { "required": ["index_name"] } },
"environment": { "not": { "required": ["index_name"] } }
}
not
-required
怎么了?
有一个关于 not
-required
如何工作的子问题。这令人困惑,因为它并不意味着它在英语中的读法,但它的相似程度足以让我们有时认为它确实如此。
在上面的例子中,如果我们把它读成"not required",听起来就像是"optional"的意思。更准确的描述是 "forbidden".
这很尴尬,但还算不错。当您想要 "forbid" 多个 属性 时,就会让人感到困惑。假设我们想说,如果 "foo" 存在,则 "bar" 和 "baz" 被禁止。您可能首先尝试的是这个。
"dependencies": {
"foo": { "not": { "required": ["bar", "baz"] } }
}
然而,这意味着如果 "foo" 存在,则实例无效,如果 "bar" AND "baz" 是当前的。他们都必须在那里触发失败。我们真正想要的是如果存在 "bar" 或 "baz" 则它无效。
"dependencies": {
"foo": {
"not": {
"anyOf": [
{ "required": ["bar"] },
{ "required": ["baz"] }
]
}
}
}
为什么这么难?
JSON 架构针对可容忍更改的架构进行了优化。模式应强制实例具有完成特定任务所需的数据。如果超过它的需要,应用程序将忽略其余部分。这样,如果将某些东西添加到实例中,一切仍然有效。如果实例有一些应用程序不使用的额外字段,它不应该验证失败。
因此,当您尝试执行类似禁止您原本可以忽略的事情时,您有点违背 JSON 架构的原则,事情可能会变得有点丑陋。然而,有时这是必要的。我对你的情况了解不多,无法打那个电话,但我猜想 dependencies
在这种情况下可能是必要的,但 additionalProperties
不是。
在我的架构中,我声明了这些属性:
"index_name": {
"type": "string",
"examples": ["foo-wwen-live", "foo"]
},
"locale": {
"type": "string",
"examples": ["wwen", "usen", "frfr"]
},
"environment": {
"type": "string",
"default": "live",
"examples": [
"staging",
"edgengram",
"test"
]
}
我希望根据我的模式验证的 JSON 主体有效 仅当 :
index_name
存在,并且locale
和environment
不存在;locale
and/orenviroment
存在,index_name
不存在 出席
简而言之,locale
和 environment
绝不能与 index_name
混用。
测试用例和期望的结果:
这些应该通过:
案例#1
{
"locale": "usen"
}
案例 #2
{
"environment": "foo"
}
案例 #3
{
"environment": "foo",
"locale": "usen"
}
案例 #4
{
"index_name": "foo-usen"
}
这些不应该通过:
案例 #5
{
"index_name": "foo-usen",
"locale": "usen"
}
案例 #6
{
"index_name": "foo-usen",
"environment": "foo"
}
案例 #7
{
"index_name": "foo-usen",
"locale": "usen",
"environment": "foo"
}
我为我的架构创建了以下规则,但它并未涵盖所有情况。例如,如果 locale
和 environment
都存在,则如果 index_name
也存在,则验证 returns 失败,根据案例 #7,这是正确的行为。但是,如果 locale
和 environment
中只有一个存在,它允许 index_name
也存在(在案例 #5 和 #6 中失败)。
"oneOf": [
{
"required": ["index_name"],
"not": {"required": ["locale", "environment"]}
},
{
"anyOf": [
{
"required": ["locale"],
"not": {"required": ["index_name"]}
},
{
"required": ["environment"],
"not": {"required": ["index_name"]}
}
]
}
]
关于 "not": {"required": []}
声明如何工作,我得到的信息很复杂。
除此规则外,我还要求在所有情况下都存在一个不相关的 属性,并且我设置了 "additionalProperties": false
。
满足我所有测试用例的规则是什么?
因为 required: [a, b]
意味着(a 必须存在且 b 必须存在)
然后 not: {required: [a, b]}
表示(不(a 必须存在且 b 必须存在))
这在逻辑上等同于(a 不得存在或 b 不得存在)。
所以这不是正确的表达方式(a 不得存在且 b 不得存在)。你需要两个 not
s.
根据您的要求,这是正确的表达方式:
{
"oneOf": [
{
"required": ["index_name"],
"allOf": [
{"not": {"required": ["locale"]}},
{"not": {"required": ["environment"]}}
]
},
{
"anyOf": [
{"required": ["locale"]},
{"required": ["environment"]}
],
"not": {
"required": ["index_name"]
}
}
]
}
依赖关系
这是 dependencies
关键字的工作。下面说
- 如果 "locale" 存在,则 "index_name" 被禁止。
- 如果 "environment" 存在,则 "index_name" 被禁止。
|
"dependencies": {
"locale": { "not": { "required": ["index_name"] } },
"environment": { "not": { "required": ["index_name"] } }
}
not
-required
怎么了?
有一个关于 not
-required
如何工作的子问题。这令人困惑,因为它并不意味着它在英语中的读法,但它的相似程度足以让我们有时认为它确实如此。
在上面的例子中,如果我们把它读成"not required",听起来就像是"optional"的意思。更准确的描述是 "forbidden".
这很尴尬,但还算不错。当您想要 "forbid" 多个 属性 时,就会让人感到困惑。假设我们想说,如果 "foo" 存在,则 "bar" 和 "baz" 被禁止。您可能首先尝试的是这个。
"dependencies": {
"foo": { "not": { "required": ["bar", "baz"] } }
}
然而,这意味着如果 "foo" 存在,则实例无效,如果 "bar" AND "baz" 是当前的。他们都必须在那里触发失败。我们真正想要的是如果存在 "bar" 或 "baz" 则它无效。
"dependencies": {
"foo": {
"not": {
"anyOf": [
{ "required": ["bar"] },
{ "required": ["baz"] }
]
}
}
}
为什么这么难?
JSON 架构针对可容忍更改的架构进行了优化。模式应强制实例具有完成特定任务所需的数据。如果超过它的需要,应用程序将忽略其余部分。这样,如果将某些东西添加到实例中,一切仍然有效。如果实例有一些应用程序不使用的额外字段,它不应该验证失败。
因此,当您尝试执行类似禁止您原本可以忽略的事情时,您有点违背 JSON 架构的原则,事情可能会变得有点丑陋。然而,有时这是必要的。我对你的情况了解不多,无法打那个电话,但我猜想 dependencies
在这种情况下可能是必要的,但 additionalProperties
不是。