JSON 有条件的架构:需要和不需要
JSON Schema conditional: require and not require
我正在尝试实现此条件:如果存在特定的 属性,则需要另一个 属性;但如果不存在,则不需要另一个。
此外,在 JSON 模式中,我们可以在依赖项中使用 not 吗?
这是一个示例架构
var schema = {
"properties": {
"smaller": {
"type": "number"
},
"larger": { "type": "number" },
"medium":{'type':'string'},
"bulky":{'type':'string'}
},
require:['smaller','larger'],
additionalProperties:false
};
如果存在 "medium",则需要 "bulky"。否则,不需要 "bulky"。
这里的"not required"表示如果"medium"不存在,那么bulky一定不存在
JSON Schema Draft-07 包含 these new keywords if
、then
和 else
,它们允许您拥有条件模式。
在这个例子中:
- 只需要
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);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.5.5/ajv.min.js"></script>
希望这是有道理的,您可以相应地调整您的代码。
PS:在您的架构中,您有 require
属性 我不确定它是否是有效的 JSON 架构关键字。您可能指的是 required
。
即使不使用 JSON Schema draft-07 if-then-else.
也有几种方法可以达到所需的效果
逻辑运算符和蕴涵(draft-04 及更高版本)
这里的逻辑含义:if "medium" present then "bulky" is required can be translated to "medium" not present OR "bulky" is "required"(后者暗示 "medium" is present)可以进一步阐述为 "medium" 不需要或 "bulky" 是 "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
查看此处以供参考:
http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.7
"anyOf" - 逻辑或,"oneOf" - 异或,"allOf" - 与,"not" - 否定,但要注意规范:
An instance is valid against this keyword if it fails to validate successfully against the schema defined by this keyword.
draft-06 - 依赖项 + 属性名称
最明显。我不确定你是否在你的问题中排除了这个,所以为了以防万一。请注意,如果您不想简单地限制有效密钥,可以使用 "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
更新
在评论中澄清后:
for draft-6 - here "not require" means that if "medium" dont exist then bulky " must not be present"
"must not" 表示防止笨重的存在。
我会改写你的条件:
1.如果 "medium" 存在 "bulky" 必须存在 -> 两个键必须同时存在
2。如果 "medium" 不存在 "bulky" 也不能 -> 两个键 不能 同时
能否"bulky"存在而"medium"不存在?
没有。见 2。反之亦然(见 1)。布尔相等(逻辑异或的补充)。
因此,如果 "bulky" 存在 - 这意味着 "medium" 必须始终存在...这意味着两者都是 必需的 或两者都是 不得要求(甚至不允许)。
由于它是 draft-06,您还可以使用 "propertyNames" 来定义允许的 属性 名称(这种逻辑的快捷方式)。
逻辑运算符和蕴涵(draft-06 及以上)
转换为 JSOn 架构的正确逻辑操作如下所示:
"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 - EITHER(两者都需要)或(中型不需要 AND bulky 不需要)。
请注意我不是在做 "not" : { "required" : ["medium","bulky"] }只有其中一个键存在,"required" 架构将失败,这意味着 "not" 将 return 成功验证结果。需要使用 de Morgans 定律重新措辞:
"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",
},
]
}
它回答了你的问题吗?
如果您有多个属性依赖于各自的值,您可以使用 属性 依赖关系。
{
"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"]
}
}
}
]
}
我正在尝试实现此条件:如果存在特定的 属性,则需要另一个 属性;但如果不存在,则不需要另一个。
此外,在 JSON 模式中,我们可以在依赖项中使用 not 吗?
这是一个示例架构
var schema = {
"properties": {
"smaller": {
"type": "number"
},
"larger": { "type": "number" },
"medium":{'type':'string'},
"bulky":{'type':'string'}
},
require:['smaller','larger'],
additionalProperties:false
};
如果存在 "medium",则需要 "bulky"。否则,不需要 "bulky"。
这里的"not required"表示如果"medium"不存在,那么bulky一定不存在
JSON Schema Draft-07 包含 these new keywords if
、then
和 else
,它们允许您拥有条件模式。
在这个例子中:
- 只需要
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);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.5.5/ajv.min.js"></script>
希望这是有道理的,您可以相应地调整您的代码。
PS:在您的架构中,您有 require
属性 我不确定它是否是有效的 JSON 架构关键字。您可能指的是 required
。
即使不使用 JSON Schema draft-07 if-then-else.
也有几种方法可以达到所需的效果逻辑运算符和蕴涵(draft-04 及更高版本)
这里的逻辑含义:if "medium" present then "bulky" is required can be translated to "medium" not present OR "bulky" is "required"(后者暗示 "medium" is present)可以进一步阐述为 "medium" 不需要或 "bulky" 是 "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
查看此处以供参考:
http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.7
"anyOf" - 逻辑或,"oneOf" - 异或,"allOf" - 与,"not" - 否定,但要注意规范:
An instance is valid against this keyword if it fails to validate successfully against the schema defined by this keyword.
draft-06 - 依赖项 + 属性名称
最明显。我不确定你是否在你的问题中排除了这个,所以为了以防万一。请注意,如果您不想简单地限制有效密钥,可以使用 "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
更新
在评论中澄清后:
for draft-6 - here "not require" means that if "medium" dont exist then bulky " must not be present"
"must not" 表示防止笨重的存在。
我会改写你的条件:
1.如果 "medium" 存在 "bulky" 必须存在 -> 两个键必须同时存在
2。如果 "medium" 不存在 "bulky" 也不能 -> 两个键 不能 同时
能否"bulky"存在而"medium"不存在?
没有。见 2。反之亦然(见 1)。布尔相等(逻辑异或的补充)。
因此,如果 "bulky" 存在 - 这意味着 "medium" 必须始终存在...这意味着两者都是 必需的 或两者都是 不得要求(甚至不允许)。
由于它是 draft-06,您还可以使用 "propertyNames" 来定义允许的 属性 名称(这种逻辑的快捷方式)。
逻辑运算符和蕴涵(draft-06 及以上)
转换为 JSOn 架构的正确逻辑操作如下所示:
"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 - EITHER(两者都需要)或(中型不需要 AND bulky 不需要)。
请注意我不是在做 "not" : { "required" : ["medium","bulky"] }只有其中一个键存在,"required" 架构将失败,这意味着 "not" 将 return 成功验证结果。需要使用 de Morgans 定律重新措辞:
"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",
},
]
}
它回答了你的问题吗?
如果您有多个属性依赖于各自的值,您可以使用 属性 依赖关系。
{
"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"]
}
}
}
]
}