【问题标题】:JSON Schema conditional: require and not requireJSON Schema 条件:需要和不需要
【发布时间】:2019-04-23 05:20:55
【问题描述】:

我正在尝试实现此条件:如果存在特定属性,则需要另一个属性;但如果它不存在,则不需要另一个。

另外,在 JSON 模式中,我们可以在依赖项中使用 not 吗?

这是一个示例架构

var schema = {
    "properties": {
        "smaller": {
            "type": "number"
        },
        "larger": { "type": "number" },
        "medium":{'type':'string'},
        "bulky":{'type':'string'}
    },
    require:['smaller','larger'],
    additionalProperties:false
};

如果存在“medium”,则需要“bulky”。否则,不需要“笨重”。

这里的“不需要”是指如果“medium”不存在,那么bulky就不能存在。

【问题讨论】:

  • 如果您提及将针对哪个草案版本的 JSON SCHEMA 进行塑造并提供示例 JSON 文档,将会有所帮助。
  • 对于draft-6 - 这里的“不需要”意味着如果“中等”不存在,那么笨重的“不能存在”
  • 查看更新的答案。如果我正确理解了您的更新,这可能会回答您的问题。

标签: jsonschema


【解决方案1】:

即使不使用 JSON Schema Draft-07 if-then-else,也有几种方法可以达到所需的效果。

逻辑运算符和蕴涵(draft-04 及以上)

这里的逻辑含义:如果存在“中等”,则需要“庞大”可以翻译成不存在“中等”或“庞大”是“必需” (后者暗示 "medium" 存在)可以进一步阐述为 "medium" not required OR "bulky" is "required"(因为如果 "medium" 是目前,满足要求的条件)。请参阅以下架构:

"properties": {
  "smaller": {"type": "number"},
  "larger": { "type": "number" },
  "medium":{"type":"string"},
  "bulky":{"type":"string"}
},
"required":["smaller","larger"],
"anyOf" : [ 
  { 
    "not" : { "required" : ["medium"] }
  },
  {
    "required" : ["bulky"]
  }
],
"additionalProperties" : false

查看这里以供参考:

JSON schema - valid if object does *not* contain a particular property

http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.7

“anyOf” - 逻辑或,“oneOf” - 异或,“allOf” - 与,“not” - 否定,但要注意规范:

如果实例未能成功验证此关键字定义的架构,则该实例对该关键字有效。

draft-06 - 依赖项 + propertyNames

最明显。我不确定您是否在问题中排除了这个问题,所以放在这里以防万一。请注意,如果您不想简单地限制有效键,则可以使用“propertyNames”而不是“additionalProperties”(实际上就是添加它的目的)。

"properties": {
  "smaller": {"type": "number"},
  "larger": { "type": "number" },
  "medium":{"type":"string"},
  "bulky":{"type":"string"}
},
"required":["smaller","larger"],
"dependencies" : {
  "medium" : ["bulky"]
},
"propertyNames" : {
  "enum" : [
    "smaller",
    "larger",
    "medium",
    "bulky"
  ]
}

查看此处以供参考:http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.7

更新

在评论中澄清后:

对于draft-6 - 这里的“不需要”意味着如果“中等”不存在,那么笨重的“一定不能存在”

“不得”表示防止出现笨重的东西。

我会改写你的条件:

1.如果 "medium" 存在 "bulky" 必须存在 -> 两个键必须同时存在

2.如果“medium”不存在“bulky”不得也存在 -> 两个键不得同时存在

“bulky”可以存在,“medium”不存在吗?

没有。见 2。反之亦然(见 1)。布尔相等(与逻辑 XOR 互补)。

因此,如果“笨重”存在 - 这意味着“中等”必须始终存在......这意味着两者都是必需的或两者都必须不是必需的(甚至是允许的)。

由于它是 06 草案,您还可以使用 "propertyNames" 来定义允许的属性名称(这种逻辑的快捷方式)。

逻辑运算符和蕴涵(draft-06 及以上)

转换为 JSOn Schema 的正确逻辑操作如下所示:

"oneOf" : [
  { "required" : ["medium","bulky"] }, <== this schema is satisfied if both keys appear in validated instance
  {
    "allOf" : [   <== !medium ^ !bulky - due to how "not" works in schema context
      {"not" : { "required" : ["medium"] } },  
      {"not" : { "required" : ["bulky"] } },
    ]
  }
]

XOR - 要么(两者都需要)要么(不需要中等大小且不需要大容量)。

请注意我没有做 "not" : { "required" : ["medium","bulky"] } 因为当只有其中一个键存在时,“必需”模式会失败,这意味着“不”将返回成功的验证结果。需要使用德摩根定律重新表述它:

"oneOf" : [
  { "required" : ["medium","bulky"] },
  {
    "not" : {   <=== !medium ^ !bulky = !(medium v bulky)
      "anyOf" : [
        { "required" : ["medium"] },
        { "required" : ["bulky"]  },
      ]
    }
  }
]

不过,使用“propertyNames”也可以解决问题。 请参阅以下架构:

{
  "$schema": "http://json-schema.org/draft-06/schema#",
  "properties": {
    "smaller": {"type": "number"},
    "larger": { "type": "number" },
    "medium":{"type":"string"},
    "bulky":{"type":"string"}
  },
  "required":["smaller","larger"],
  "anyOf" : [ 
    { 
       "required" : ["medium","bulky"]
    },
    {
      "propertyNames" : {
        "enum" : [
          "smaller",
          "larger"
        ]
      },
    }
  ],
  "examples" : [
    {
      "smaller" : 1,
      "larger" : 2,


    },
    {
      "smaller" : 1,
      "larger" : 2,
      "bulky" : "test",
      "medium" : ""
    },
    {
      "smaller" : 1,
      "larger" : 2,

      "medium" : ""
    },
    {
      "smaller" : 1,
      "larger" : 2,
      "bulky" : "test",

    },
  ]
}

它回答了你的问题吗?

【讨论】:

  • 很高兴我能帮上忙。如果我可以为未来提出一些建议:尝试用布尔表达式写下你的条件。正确描述主题通常会立即揭示解决方案。
【解决方案2】:

JSON Schema Draft-07 包含 these new keywordsifthenelse,它们允许您拥有条件模式。

在这个例子中:

  • 只需要foo 属性
  • 但是,如果 foo 设置为 "bar",则 bar 属性也成为必需的

var ajv = new Ajv({
  allErrors: true
});

var schema = {
  "properties": {
    "foo": {
      "type": "string"
    },
    "bar": {
      "type": "string"
    },

  },
  "required": ["foo"],
  "if": {
    "properties": {
      "foo": {
        "enum": ["bar"]
      }
    }
  },
  "then": {
    "required": ["bar"]
  }
}

var validate = ajv.compile(schema);

test({
  "foo": "bar",
  "bar": "baz"
}); // VALID

test({
  "foo": "xyz"
}); // VALID

test({
  "foo": "bar",
}); // NOT VALID


function test(data) {
  var valid = validate(data);
  if (valid) console.log('VALID', data);
  else console.log('NOT VALID', data);
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.5.5/ajv.min.js"&gt;&lt;/script&gt;

希望这是有道理的,您可以相应地调整您的代码。

PS:在您的架构中,您有 require 属性,我不确定它是否是有效的 JSON 架构关键字。你可能指的是required

【讨论】:

    【解决方案3】:

    如果你有多个属性依赖于各自的值,你可以使用属性依赖。

    {
      "type": "object",
      "properties": {
        "weight_1": {
            "type": "integer"
        },
        "weight_2": {
            "type": "integer"
        },
        "description_1": {
            "type": "string" 
        },
        "description_2": {
            "type": "string" 
        }
      },
      "allOf": [
        {
            "if": {
              "properties": {
                "weight_1": {
                    "minimum": 10 
                }
              }
            },
            "then": {
              "dependencies": {
                "weight_1": ["description_1"]
              }
            }
        },
        {
            "if": {
              "properties": {
                "weight_2": {
                    "minimum": 100
                }
              }
            },
            "then": {
              "dependencies": {
                "weight_2": ["description_2"]
              }
            }
        }
      ]
    }
    

    【讨论】:

    • 如果情况是检查属性值是否至少为 10 则此答案很有帮助,那么依赖项是必需的,但实际的问题陈述是检查键是否存在。
    猜你喜欢
    • 2020-06-09
    • 2019-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-24
    • 1970-01-01
    • 2015-09-01
    • 2021-10-21
    相关资源
    最近更新 更多