简体   繁体   English

JSON 没有要求的模式之一

[英]JSON Schema oneof without required

In JSON Schema draft 7 or 8 what is the right way to say that we want optionally either one of the attributes but not both.JSON Schema草案 7 或 8 中,正确的说法是我们想要可选的属性之一而不是两者。 I can construct with required keyword, but then you have to include either one of the required attributes.我可以用required关键字构造,但是你必须包含其中一个必需的属性。 This is what I can think of, is this correct?这是我能想到的,这是正确的吗?

In this example I'm trying to validate field_1 is required and we want either one of field_2 , field_3 or none of them.在这个例子中,我试图验证field_1是必需的,我们想要field_2field_3之一,或者都不想要。 (see examples) (见例子)

{
  "$schema": "http://json-schema.org/draft-08/schema#",
  "type": "object",
  "properties": {
    "field_1": {
      "type": "string"
    },
    "field_2": {
      "type": "string"
    },
    "field_3": {
      "type": "string"
    }
  },
  "required": [
    "field_1"
  ],
  "oneof": [
    {
      "properties": [
        "field_2"
      ]
    },
    {
      "properties": [
        "field_3"
      ]
    }
  ],
  "additionalProperties": false,
  "examples": [
    {
      "field_1": "1",
      "field_2": "2"
    },
    {
      "field_1": "1",
      "field_3": "3"
    },
    {
      "field_1": "1"
    }
  ]
}

[EDITED - SEE THIRD SOLUTION BELOW] [已编辑 - 请参阅下面的第三个解决方案]

Solution 1 - At least one, but not both (verbose)解决方案 1 - 至少一个,但不是两个(详细)

I would add an allOf with a nested oneOf :我会添加一个带有嵌套allOfoneOf

{
  ...
  "allOf": [
    {
      "oneOf": [
        {"required": ["field_2"]},
        {"required": ["field_3"]}
      ],
    },
    {
      "not": {
        "required": ["field_2", "field_3"]
      }
    }
  ],
  ...
}

This requires that one of the two fields are present, but not both.这要求两个字段之一存在,但不能同时存在。


Solution 2 - At least one, but not both解决方案 2 - 至少一个,但不是两个

I think this can be further simplified by using just the oneOf :我认为这可以通过仅使用oneOf进一步简化:

{
  ...
  "oneOf": [
    {"required": ["field_2"]},
    {"required": ["field_3"]}
  ],
  ...
}
  • If neither are there, then these will both fail, and the oneOf fails.如果两者都不存在,那么这些都将失败,并且oneOf失败。
  • If one is there, then the oneOf passes.如果有一个,那么oneOf会通过。
  • If both are there, then both of these will pass, and the oneOf fails.如果两者都存在,那么这两个都会通过,而oneOf失败。

Yeah, this is better.是的,这更好。 Looking at what you had, I think this is what you were trying to do, so you were really close!看看你所拥有的,我认为这就是你想要做的,所以你真的很接近!


Solution 3 - At most one解决方案 3 - 最多一个

To pass when neither field are present you need the first solution, but change the allOf to an anyOf :要在两个字段都不存在时通过,您需要第一个解决方案,但将allOf更改为anyOf

{
  ...
  "anyOf": [
    {
      "oneOf": [
        {"required": ["field_2"]},
        {"required": ["field_3"]}
      ],
    },
    {
      "not": {
        "required": ["field_2", "field_3"]
      }
    }
  ],
  ...
}
  • If neither are there, then the not subschema will pass, and the anyOf passes.如果两者都不存在,则not子模式将通过,并且anyOf将通过。
  • If one is there, then the oneOf subschema will pass, and the anyOf passes.如果有一个,那么oneOf子模式将通过,而anyOf将通过。
  • If both are there, then如果两者都存在,那么
    • both of the oneOf subschemas will pass, so the oneOf fails oneOf子模式都将通过,因此oneOf失败
    • the not subschema will fail非子模式将not
    • so the anyOf fails所以anyOf失败了

You can test these solutions here您可以在此处测试这些解决方案

Here's a couple more options to add to @gregdennis's answer.这里有几个选项可以添加到@gregdennis 的答案中。

Dependencies依赖项

This is a great use case for the dependencies keyword.这是dependencies关键字的一个很好的用例。 This says, "if there is a "field_2" there can't be a "field_3" and, "if there is a "field_3" there can't be a "field_2".这就是说,“如果有一个“field_2”,就不可能有一个“field_3”,并且,“如果有一个“field_3”,就不可能有一个“field_2”。 If neither "field_2" or "field_3" exist, no constraints apply and the schema passes.如果“field_2”或“field_3”都不存在,则不应用任何约束并且架构通过。

"dependencies": {
  "field_2": { "not": { "required": ["field_3"] } },
  "field_3": { "not": { "required": ["field_2"] } }
}

maxProperties最大属性

This one is a bit hacky, but it has the benefit of being a one liner.这个有点老套,但它的好处是成为一个班轮。 If "field_1" is required and only one of "field_2" or "field_2" are allowed, there can not be more than two properties present in this object.如果需要“field_1”并且只允许“field_2”或“field_2”其中之一,则此对象中的属性不能超过两个。 Beware, this solution might be more clever than it's worth.当心,这个解决方案可能比它的价值更聪明。 Because this constraint works indirectly, it can be lead to maintenance difficulties in the future.由于此约束间接起作用,因此可能会导致将来的维护困难。

"maxProperties": 2

if/then如果/那么

This is just a more verbose version of the dependencies options, but might be more descriptive for someone reading the schema.这只是dependencies项选项的更详细版本,但对于阅读架构的人来说可能更具描述性。

"allOf": [
  {
    "if": { "required": ["field_2"] },
    "then": { "not": { "required": ["field_3"] } }
  },
  {
    "if": { "required": ["field_3"] },
    "then": { "not": { "required": ["field_2"] } }
  }
]

I had to try to figure this out for 3 fields where field 1 is also optional.我不得不尝试为 3 个字段解决这个问题,其中字段 1 也是可选的。 Doing so revealed @gregdennis's answer to Solution 3 was slightly more than it needed to be, this accomplishes the same goal as there is no need to check for required single values as neither are required.这样做揭示了@gregdennis 对解决方案 3的回答比它需要的略多,这实现了相同的目标,因为不需要检查所需的单个值,因为两者都不需要。

{
  ...
  "not": {
    "required": ["field_2", "field_3"]
  } 
  ...
}

To do this for 3, it looks like:要为 3 执行此操作,它看起来像:

{
  ...
  "not": {
    "anyOf": [{
      "required": ["field_1", "field_2", "field_3"]
    },
    {
      "required": ["field_1", "field_2"]
    },
    {
      "required": ["field_2", "field_3"]
    },
    {
      "required": ["field_1", "field_3"]
    }]
  }
  ...
}

As you add more fields, this obviously becomes less useful.随着您添加更多字段,这显然变得不那么有用。 So a better solution with room to go to N is the following:因此,有空间去 N 的更好解决方案如下:

{
  ...
  "anyOf": [
    {
      "oneOf": [
        {"required": ["field_1"]},
        {"required": ["field_2"]},
        {"required": ["field_3"]}
      ]
    },
    {
      "not": {
        "anyOf": [
          {"required": ["field_1"]},
          {"required": ["field_2"]},
          {"required": ["field_3"]}
        ]
      }
    }
  ]
  ...
}

You can play with it here .你可以在这里玩。

You can do this as follows:您可以按如下方式执行此操作:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "field_1": {
      "type": "string"
    }
  },
  "oneOf": [
    {
      "properties": {

      },
      "additionalProperties": false
    },
    {
      "properties": {
        "field_2": {
          "type": "string"
        }
      },
      "required": ["field_2"],
      "additionalProperties": false
    },
    {
      "properties": {
        "field_3": {
          "type": "string"
        }
      },
      "required": ["field_3"],
      "additionalProperties": false
    }
  ],
  "required": [
    "field_1"
  ]
}

As stated in this book : "oneOf: (XOR) Must be valid against exactly one of the subschemas".本书所述:“oneOf: (XOR) 必须对其中一个子模式有效”。

  1. I added the field_1 to the "main" schema and marked this field as required.我将 field_1 添加到“主”模式并根据需要标记此字段。
  2. I described three subschemas.我描述了三个子模式。
  • The first schema without required fields.没有必填字段的第一个模式。
  • The second schema with required "field_2" field.具有必需的“field_2”字段的第二个模式。
  • The third schema with required "field_3" field.具有必需的“field_3”字段的第三个模式。
  1. For all subschemas I set the "additionalProperties" in the value false .对于所有子模式,我将“additionalProperties”设置为值false

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM