有条件地需要jsonSchema属性

tom*_*ern 79 jsonschema

在jsonSchema中,您可以使用"required"属性指示已定义的字段是否为必填字段:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "header": {
            "type": "object",
            "properties": {
                "messageName": {
                    "type": "string"
                },
                "messageVersion": {
                    "type": "string"
                }
            },
            "required": [
                "messageName",
                "messageVersion"
            ]
        }
    },
    "required": [
        "header"
    ]
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,我希望messageVersion字段不是必需的.有没有办法让这个领域的强制性有条件?

Jas*_*ers 211

根据您的情况,有几种不同的方法.我可以想到有条件地要求一个领域的四种不同方式.

依赖

dependencies关键字是所述的一个条件变化required关键字.Foreach属性dependencies,如果该属性存在于要验证的JSON中,则与该键关联的模式也必须有效. 如果存在"foo"属性,则需要"bar"属性

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependencies": {
    "foo": { "required": ["bar"] }
  }
}
Run Code Online (Sandbox Code Playgroud)

如果架构仅包含required关键字,则还有一个简短形式.

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependencies": {
    "foo": ["bar"]
  }
}
Run Code Online (Sandbox Code Playgroud)

意义

如果您的条件取决于字段的值,则可以使用名为implication的布尔逻辑概念."A暗示B"实际上意味着,如果A为真,则B也必须为真.含义也可以表示为"!A或B". "foo"属性不等于"bar",或者"bar"属性是必需的.或者,换句话说:如果"foo"属性等于"bar",则需要"bar"属性

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "anyOf": [
    {
      "not": {
        "properties": {
          "foo": { "const": "bar" }
        },
        "required": ["foo"]
      }
    },
    { "required": ["bar"] }
  ]
}
Run Code Online (Sandbox Code Playgroud)

如果"foo"不等于"bar",则#/anyOf/0匹配和验证成功.如果"foo"等于"bar",则#/anyOf/0失败并且#/anyOf/1必须对anyOf验证成功有效.

枚举

如果您的条件是基于枚举,那么它更直接. "foo"可以是"bar"或"baz".如果"foo"等于"bar",则需要"bar".如果"foo"等于"baz",则需要"baz".

{
  "type": "object",
  "properties": {
    "foo": { "enum": ["bar", "baz"] },
    "bar": { "type": "string" },
    "baz": { "type": "string" }
  },
  "anyOf": [
    {
      "properties": {
        "foo": { "const": "bar" }
      },
      "required": ["bar"]
    },
    {
      "properties": {
        "foo": { "const": "baz" }
      },
      "required": ["baz"]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

IF-THEN-ELSE

一个相对较新除了JSON模式(草案-07)增加了if,thenelse关键字. 如果"foo"属性等于"bar",则需要"bar"属性

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "if": {
    "properties": {
      "foo": { "const": "bar" }
    },
    "required": ["foo"]
  },
  "then": { "required": ["bar"] }
}
Run Code Online (Sandbox Code Playgroud)

编辑12/23/2017:更新了蕴涵部分,并添加了If-Then-Else部分.

  • @scubbo我不是'if-then-else`关键字的粉丝,我拒绝使用它们.但是,如果您选择使用它,我建议始终将它们包装在只包含这三个关键字的`allOf`中.`{... other_keywords ...,"allOf":[{"if":...,"then":...,"else":...}],... more_keywords ...} ` (5认同)
  • @ClayBridges评论部分不是讨论的正确位置,但这是短版本.作为一般规则,JSON Schema关键字是无状态的.否可以使用关键字值以外的信息来验证实例.`if`,`then`和`else`违反了这个规则,因为它们相互依赖. (5认同)
  • 谷歌搜索条件 json 模式并被引导到这里。很棒的答案,用简单的例子涵盖了所有方面。做得好。 (3认同)
  • @Jason 为什么不是`if ...` 的粉丝?我认为在您的回答中对此发表简短意见是完全合理的。或者这是一个很长的故事? (2认同)
  • @GGirard,这是我所知道的在JSON模式中使用这些模式的最佳方法。布尔运算已正式记录,但其余只是数学运算。`allOf` == AND,`anyOf` == OR,`oneOf` == XOR和`not` == NOT。您可以在“布尔代数”上搜索Google,以获取有关数学知识的更多资源(例如蕴涵)。 (2认同)
  • @AlexeyShrub 我一直想写这个,但被其他事情分散了注意力。我是条件的 _idea_ 的粉丝。它确实让人们更容易理解。我反对将它定义为三个独立的 _stateful_ 关键字的方式(请参阅之前的评论)。拥有违反其他关键字遵循的架构属性的关键字会使 JSON 模式验证器更难实现且效率更低。如果条件以一种不同的无状态方式定义,那么我不会反对。 (2认同)

tob*_*ora 5

截至 2022 年,dependencies弃用,并分为dependentRequired(参见例如本示例) 和dependentSchemas(参见例如本示例)。只需使用即可dependentRequired解决问题:

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependentRequired": {
    "foo": ["bar"]
  }
}
Run Code Online (Sandbox Code Playgroud)