如何根据 JSON Schema 中其他属性的存在有条件地禁止属性?

Mak*_*ski 8 validation json jsonschema

在我的模式中,我声明了这些属性:

"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"
      ]
}
Run Code Online (Sandbox Code Playgroud)

我希望根据我的模式验证的 JSON 主体仅在以下情况下才有效:

  • index_name 存在,并且两者 localeenvironment 存在;
  • locale和/或enviroment 存在,并且index_name 存在

总之,localeenvironment绝不应该以混合index_name

测试用例和预期结果:

这些应该通过:
案例#1

{
  "locale": "usen"
}
Run Code Online (Sandbox Code Playgroud)

案例#2

{
  "environment": "foo"
}
Run Code Online (Sandbox Code Playgroud)

案例#3

{
  "environment": "foo",
  "locale": "usen"
}
Run Code Online (Sandbox Code Playgroud)

案例#4

{
  "index_name": "foo-usen"
}
Run Code Online (Sandbox Code Playgroud)

这些不应该通过:
案例#5

{
  "index_name": "foo-usen",
  "locale": "usen"
}
Run Code Online (Sandbox Code Playgroud)

案例#6

{
  "index_name": "foo-usen",
  "environment": "foo"
}
Run Code Online (Sandbox Code Playgroud)

案例#7

{
  "index_name": "foo-usen",
  "locale": "usen",
  "environment": "foo"
}
Run Code Online (Sandbox Code Playgroud)

我为我的架构创建了以下规则,但它并未涵盖所有情况。例如,如果localeenvironment都存在,如果index_name也存在,验证返回失败,这是根据案例#7 的正确行为。但是,如果只存在localeand之一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"]}
        }
      ]
    }
  ]
Run Code Online (Sandbox Code Playgroud)

我收到关于"not": {"required": []}声明如何工作的混合信息。有些人声称这意味着它禁止存在数组中声明的任何内容,这与语法给出的想法相反。其他声称这应该完全按照听起来的方式进行:不需要数组中列出的属性- 它们可以存在,但如果它们不存在也没关系。

除了这条规则之外,我还要求在所有情况下都存在一个不相关的属性,并且我设置了"additionalProperties": false.

满足我所有测试用例的规则是什么?

Jas*_*ers 9

依赖关系

这是dependencies关键字的工作。下面说

  • 如果存在“locale”,则禁止“index_name”。
  • 如果存在“environment”,则禁止使用“index_name”。

|

"dependencies": {
  "locale": { "not": { "required": ["index_name"] } },
  "environment": { "not": { "required": ["index_name"] } }
}
Run Code Online (Sandbox Code Playgroud)

用什么的了not- required

有一个关于如何分的问题not-required工作。它令人困惑,因为它并不意味着它在英语中的阅读方式,但它的相似之处足以让我们有时认为它是这样。

在上面的例子中,如果我们把它读为“非必需”,听起来它的意思是“可选”。更准确的描述是“禁止”。

这很尴尬,但也不算太糟糕。令人困惑的地方是当您想“禁止”多个属性时。假设我们想说,如果存在“foo”,则禁止使用“bar”和“baz”。你可以尝试的第一件事是这个。

"dependencies": {
  "foo": { "not": { "required": ["bar", "baz"] } }
}
Run Code Online (Sandbox Code Playgroud)

然而,这意味着如果“foo”存在,那么如果“bar”“baz”都存在,则实例无效。他们都必须在那里触发失败。我们真正想要的是如果存在“bar”“baz” ,它就无效。

"dependencies": {
  "foo": {
    "not": {
      "anyOf": [
        { "required": ["bar"] },
        { "required": ["baz"] }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

为什么这么难?

JSON Schema 针对可以容忍变化的模式进行了优化。模式应该强制实例具有完成特定任务所需的数据。如果它比它需要的多,应用程序会忽略其余的。这样,如果向实例添加了一些东西,一切仍然有效。如果实例有一些应用程序不使用的额外字段,则验证不应该失败。

因此,当您尝试执行诸如禁止您可以忽略的事情之类的事情时,您会有点违反 JSON Schema 的原则,事情可能会变得有点难看。然而,有时这是必要的。我不太了解您的情况,无法拨打电话,但我想dependencies在这种情况下可能有必要,但事实additionalProperties并非如此。