假设我们有以下模式(从教程这里):
{
"$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
的任何附加字段都是无效的。我知道为此目的存在additionalProperties
,它应该设置为"false"。但是当我设置"additionalProprties":false
如下:
"shipping_address": {
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
],
"additionalProperties":false
}
我收到验证错误(选中here):
[ {
"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
部分的字段?提前感谢。
5条答案
按热度按时间yqkkidmi1#
[此处为v4确认规范草案的作者]
您偶然发现了JSON Schema中最常见的问题,即它根本无法像用户期望的那样进行继承;但同时也是它的核心特征之一。
当您这样做时:
schema1
和schema2
彼此 * 不 * 知道;它们在其自身的背景下被评估。在您的场景中(许多人都会遇到),您希望
schema1
中定义的属性将为schema2
所知;但事实并非如此,也永远不会如此。这就是为什么我对草案v5提出这两项建议:
strictProperties
,merge
.shipping_address
的模式将为:以及在
address
中定义strictProperties
到true
。顺便说一句,我也是你所指网站的作者。
现在,让我回到草案v3,草案v3确实定义了
extends
,它的值是一个模式或模式数组,通过定义这个关键字,它意味着示例必须对当前模式 * 和 * 在extends
中指定的所有模式有效;基本上,草案v4的allOf
是草案v3的extends
。请考虑以下内容(草案v3):
现在,
它们是一样的。或者是那样?
或者那个?
总而言之,这意味着draft v3中的
extends
从来没有真正做到人们期望它做的事情,而有了draft v4,*Of
关键字得到了明确的定义。但你遇到的问题是迄今为止最常见的问题,因此我的建议将一劳永逸地消除这一误解的根源!
waxmsbnn2#
additionalProperties
适用于 * 直接模式 * 中properties
或patternProperties
未说明的所有属性。这意味着,当您具有:
additionalProperties
在这里适用于 all 属性,因为没有兄弟级别的properties
条目-allOf
中的条目不计算在内。您可以做的一件事是将
properties
定义上移一级,并为要导入的属性提供存根条目:这意味着
additionalProperties
将不适用于所需的属性。hc8w905p3#
下面是Yves-M's Solution的一个稍微简化的版本:
这保留了对基本
address
模式中所需属性的验证,而只是在shipping_address
中添加了所需的type
属性。不幸的是,
additionalProperties
只考虑了直接的、兄弟级别的属性,也许这是有原因的,但这就是为什么我们需要重复继承的属性。这里,我们使用空对象语法,以简化的形式重复继承的属性。这意味着具有这些名称的属性将是有效的,无论它们包含什么类型的值。但是我们可以依赖于
allOf
关键字来实施在基本address
模式中声明的类型约束(以及任何其他约束)。bfrts1fy4#
不要在定义级别设置additionalProperties=false
一切都会好起来的:
您的每个
billing_address
和shipping_address
都应该指定它们自己所需的属性。如果您想将
"additionalProperties": false
的属性与其他属性合并,则您的定义不应包含"additionalProperties": false
。z3yyvxxp5#
由于没有人发布规范2019-09及以上的有效答案,我几乎错过了Andreas H.的评论;
作者在这里可以找到一个相当清晰简洁的解释;