我有以下示例架构:
{
"id": "http://schema.acme.com/widgets",
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"bentWidget": {
"type": "object",
"required": ["angle", "baseWidget"],
"properties": {
"angle": {
"type": "number",
"minimum": 0,
"maximum": 90
},
"baseWidget": {
"$ref": "#/definitions/baseWidget"
}
}
},
"highPowerWidget": {
"type": "object",
"required": ["power", "baseWidget"],
"properties": {
"power": {
"type": "number",
"minimum": 101,
"maximum": 200
},
"baseWidget": {
"$ref": "#/definitions/baseWidget"
}
}
},
"color": {
"description": "the color of a widget",
"type": "string"
},
"baseWidget": {
"description": "The base type for a widget",
"type": "object",
"required": [
"title",
"version",
"colors"
],
"properties": {
"title": {
"type": "string",
"maximum": 100,
"minimum": 1,
"pattern": "^[a-zA-Z]+((_[a-zA-Z]+)*|([a-zA-Z]+_)*|_)"
},
"flanged": {
"type": "boolean"
},
"version": {
"type": "string",
"maximum": 64,
"minimum": 1
},
"colors": {
"type": "array",
"items": {
"$ref": "#/definitions/color"
}
}
}
}
},
"anyOf": [
{ "$ref": "#/definitions/baseWidget" },
{ "$ref": "#/definitions/bentWidget" },
{ "$ref": "#/definitions/highPowerWidget" }
]
}
我想测试一下,所以我把它写到一个文件中:
{
"type": "highPowerWidget",
"title": "foobar",
"version": "foo"
}
然后我从shell运行ajv
$ ajv -s widgetSchema.json -d widget-highPower.json
widget-highPower.json valid
它告诉我它是有效的,这是不正确的,highPowerWidget必须具有power属性,以及“继承”版本和colors属性。
我能够通过删除anyOf部分并输入类似的内容来测试我的个人模式:
"properties": {
"testObject": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/baseWidget" },
{ "$ref": "#/definitions/bentWidget" },
{ "$ref": "#/definitions/highPowerWidget" }
]
}
},
"required": [ "testObject" ]
并验证此JSON:
{
"testObject": {
"type" : "highPowerWidget",
"title" : "title",
"version" : "baz",
"colors" : [ "red", "green", "blue"],
"flanged" : true
}
}
但这似乎有两个原因。
我认为我对如何编写或至少测试我的模式有一个基本的误解。我的目标是拥有一组全部验证的对象,以及一组全部失败的文件。这样我就可以对我的架构进行单元测试。
答案 0 :(得分:2)
您的架构有效。如上所述,这将是一个有效的highPowerWidget:
{
"power": 150,
"baseWidget":{
"title": "SuperHighPower",
"flanged":true,
"version": "version 1",
"colors":["blue"]
}
}
我认为误解是JSONSchema不支持OO style inheritance。
相反,这个架构实际上是在highPowerWidget或bentWidget上要求“baseWidget”属性。 AJV Here's a sandbox plnkr你可以用它来测试它。
编辑:只是想一想,你可以完成这个从bentWidget和highPowerWidget中删除baseWidget属性,而是将"allOf":[{"$ref":"#/definitions/baseWidget"}]
添加到每个子窗口小部件。这将要求他们传递baseWidget的架构。所以你的架构将是:
{
"id": "http://schema.acme.com/widgets",
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"bentWidget": {
"type": "object",
"required": ["angle"],
"properties": {
"angle": {
"type": "number",
"minimum": 0,
"maximum": 90
}
},
allOf: [{
"$ref": "#/definitions/baseWidget"
}]
},
"highPowerWidget": {
"type": "object",
"required": ["power"],
"properties": {
"power": {
"type": "number",
"minimum": 101,
"maximum": 200
}
},
allOf: [{
"$ref": "#/definitions/baseWidget"
}]
},
"color": {
"description": "the color of a widget",
"type": "string"
},
"baseWidget": {
"description": "The base type for a widget",
"type": "object",
"required": [
"title",
"version",
"colors"
],
"properties": {
"title": {
"type": "string",
"maximum": 100,
"minimum": 1,
"pattern": "^[a-zA-Z]+((_[a-zA-Z]+)*|([a-zA-Z]+_)*|_)"
},
"flanged": {
"type": "boolean"
},
"version": {
"type": "string",
"maximum": 64,
"minimum": 1
},
"colors": {
"type": "array",
"items": {
"$ref": "#/definitions/color"
}
}
}
}
},
"anyOf": [{
"$ref": "#/definitions/baseWidget"
}, {
"$ref": "#/definitions/bentWidget"
}, {
"$ref": "#/definitions/highPowerWidget"
}]
}
答案 1 :(得分:2)
这里的问题是您实际上没有为"type"
字段声明架构。您的架构中没有任何内容表明"type": "highPoweredWidget"
的实例需要与"#/definitions/highPoweredWidget"
架构匹配。 "definitions"
下的架构名称仅用于查找"$ref"
的架构名称。它们实际上并未直接用于验证。
由于您使用的是draft-06,因此可以使用"const"
关键字来实现此目的。在前面的答案的基础上,我应该工作:
{
"id": "http://schema.acme.com/widgets",
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"bentWidget": {
"type": "object",
"required": ["angle"],
"properties": {
"type": {"const": "bentWidget"},
"angle": {
"type": "number",
"minimum": 0,
"maximum": 90
}
},
allOf: [{
"$ref": "#/definitions/baseWidget"
}]
},
"highPowerWidget": {
"type": "object",
"required": ["power"],
"properties": {
"type": {"const": "highPowerWidget"},
"power": {
"type": "number",
"minimum": 101,
"maximum": 200
}
},
allOf: [{
"$ref": "#/definitions/baseWidget"
}]
},
"color": {
"description": "the color of a widget",
"type": "string"
},
"baseWidget": {
"description": "The base type for a widget",
"type": "object",
"required": [
"title",
"version",
"colors"
],
"properties": {
"title": {
"type": "string",
"maximum": 100,
"minimum": 1,
"pattern": "^[a-zA-Z]+((_[a-zA-Z]+)*|([a-zA-Z]+_)*|_)"
},
"flanged": {
"type": "boolean"
},
"version": {
"type": "string",
"maximum": 64,
"minimum": 1
},
"colors": {
"type": "array",
"items": {
"$ref": "#/definitions/color"
}
}
}
}
},
"anyOf": [{
"$ref": "#/definitions/baseWidget"
}, {
"$ref": "#/definitions/bentWidget"
}, {
"$ref": "#/definitions/highPowerWidget"
}]
}
这将确保如果您的实例具有"type": "highPowerWidget"
,那么它将具有" power"属性。
我没有为" baseWidget"添加"const"
类型字段,因此它将匹配任何类型,就我所知,这似乎是正确的。
请注意,在草案07(周一发布,我认为支持ajv的beta版)中,您可以使用"if"
"then"
和"else"
个关键字来更明确地说明这一点