![](/img/trans.png)
[英]What is the difference between additionalItems and additionalProperties in JSON Schema?
[英]JSON schema : "allof" with "additionalProperties"
假设我们有遵循模式的模式(来自这里的教程):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
]
}
}
}
这是有效的实例:
{
"shipping_address": {
"street_address": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC",
"type": "business"
}
}
我需要确保shipping_address
的任何其他字段都无效。 我知道为此目的存在应设置为“false”的additionalProperties
属性。 但是当我设置"additionalProprties":false
时,如下所示:
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
],
"additionalProperties":false
}
我收到一个验证错误(在此处检查):
[ {
"level" : "error",
"schema" : {
"loadingURI" : "#",
"pointer" : "/properties/shipping_address"
},
"instance" : {
"pointer" : "/shipping_address"
},
"domain" : "validation",
"keyword" : "additionalProperties",
"message" : "additional properties are not allowed",
"unwanted" : [ "city", "state", "street_address", "type" ]
} ]
问题是:我应该如何仅限制shipping_address
部分的字段? 提前致谢。
[此处是 v4 验证规范草案的作者]
您偶然发现了 JSON Schema 中最常见的问题,即它根本无法按照用户期望的方式进行继承; 但同时它也是它的核心功能之一。
当你这样做时:
"allOf": [ { "schema1": "here" }, { "schema2": "here" } ]
schema1
和schema2
彼此不知道; 他们在自己的背景下进行评估。
在许多人遇到的场景中,您希望schema1
中定义的属性将为schema2
所知; 但事实并非如此,而且永远不会如此。
这个问题就是为什么我在 v5 草案中提出了这两个建议:
strictProperties
的属性,merge
。 您的shipping_address
架构将是:
{
"merge": {
"source": { "$ref": "#/definitions/address" },
"with": {
"properties": {
"type": { "enum": [ "residential", "business" ] }
}
}
}
}
以及在address
strictProperties
定义为true
。
顺便说一句,我也是您所指网站的作者。
现在,让我回到草稿 v3。 Draft v3 确实定义了extends
,它的值要么是一个模式,要么是一个模式数组。 通过这个关键字的定义,这意味着实例必须对当前模式和在extends
中指定的所有模式有效; 基本上,草案 v4 的allOf
是草案 v3 的extends
。
考虑一下(草案 v3):
{
"extends": { "type": "null" },
"type": "string"
}
现在,那:
{
"allOf": [ { "type": "string" }, { "type": "null" } ]
}
他们是一样的。 或者也许是这样?
{
"anyOf": [ { "type": "string" }, { "type": "null" } ]
}
或者那个?
{
"oneOf": [ { "type": "string" }, { "type": "null" } ]
}
总而言之,这意味着草案 v3 中的extends
从未真正做到人们期望它做的事情。 在草案 v4 中, *Of
关键字已明确定义。
但是到目前为止,您遇到的问题是最常遇到的问题。 因此,我的建议将一劳永逸地消除这种误解的根源!
additionalProperties
适用于直接模式中的properties
或patternProperties
属性未考虑的所有属性。
这意味着当您拥有:
{
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
],
"additionalProperties":false
}
这里的additionalProperties
适用于所有属性,因为没有兄弟级别的properties
条目- allOf
里面的那个不算。
您可以做的一件事是将properties
定义向上移动一级,并为您正在导入的属性提供存根条目:
{
"allOf": [{"$ref": "#/definitions/address"}],
"properties": {
"type": {"enum": ["residential", "business"]},
"addressProp1": {},
"addressProp2": {},
...
},
"required": ["type"],
"additionalProperties":false
}
这意味着additionalProperties
将不适用于您想要的属性。
这是Yves-M 解决方案的略微简化版本:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"street_address",
"city",
"state"
]
}
},
"type": "object",
"properties": {
"billing_address": {
"$ref": "#/definitions/address"
},
"shipping_address": {
"allOf": [
{
"$ref": "#/definitions/address"
}
],
"properties": {
"type": {
"enum": [
"residential",
"business"
]
},
"street_address": {},
"city": {},
"state": {}
},
"required": [
"type"
],
"additionalProperties": false
}
}
}
这保留了基address
模式中所需属性的验证,并仅在shipping_address
中添加所需的type
属性。
不幸的是, additionalProperties
只考虑了直接的兄弟级属性。 也许这是有原因的。 但这就是为什么我们需要重复继承的属性。
在这里,我们使用空对象语法以简化形式重复继承的属性。 这意味着具有这些名称的属性无论包含何种值都是有效的。 但是我们可以依靠allOf
关键字来强制执行基address
模式中声明的类型约束(以及任何其他约束)。
一切都会好起来的:
{
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"billing_address": {
"allOf": [
{ "$ref": "#/definitions/address" }
],
"properties": {
"street_address": {},
"city": {},
"state": {}
},
"additionalProperties": false
"required": ["street_address", "city", "state"]
},
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{
"properties": {
"type": {
"enum": ["residential","business"]
}
}
}
],
"properties": {
"street_address": {},
"city": {},
"state": {},
"type": {}
},
"additionalProperties": false
"required": ["street_address","city","state","type"]
}
}
}
您的每个billing_address
和shipping_address
都应指定自己的必需属性。
你的定义不应该有"additionalProperties": false
如果你想将他的属性与其他属性结合起来。
由于没有人为规范2019-09及更高版本发布有效答案,我几乎错过了 Andreas H. 的评论;
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
// additionalProperties: false // <-- Remove completely if present
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": {
"unevaluatedProperties": false, // <-- Add to same level as allOf as false
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
]
}
}
}
作者在这里可以找到一个非常清晰简洁的解释;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.