我正在考虑将JSON Schemas用于即将开展的项目,并寻找一种方法来验证JSON Schema文件中的命名约定/样式和一致性规则。与StyleCop或Checkstyle有些相似。
使用JSON Schema Lint中的样本来说明:
{
"description": "Any validation failures are shown in the right-hand Messages pane.",
"type": "object",
"properties": {
"foo": {
"type": "number"
},
"bar": {
"type": "string",
"enum": [
"a",
"b",
"c"
]
}
}
}
想象一下,另一位开发人员想要添加一个新属性,但我想阻止属性名称为大写(baz
而不是Baz
)或者boolean
属性应该从"是" (isBaz
)。有没有办法进行单元测试" JSON Schema文件并检查它?
"Baz": {
"type": "boolean"
},
感觉就像是JSON Schema文件的自定义验证器(与使用JSON Schema验证JSON输出相比)。这样的事情是否已经存在,或者我是否只是自己解析JSON模式文件并编写规则?
答案 0 :(得分:1)
完全有可能编写一个元模式来对您的模式强制执行此约束。让我们一步一步地构建它:
关键部分是使用patternProperties
指定允许的属性名称,additionalProperties
禁止其他任何属性:
{
"patternProperties": {
"^[a-z]+([A-Z][a-z]*)*$": {}
},
"additionalProperties": false
}
(对于这个例子,我使用了正则表达式^[a-z]+([A-Z][a-z]*)*$
来检测仅字母的lowerCamelCase)
请注意,是否为适当命名的属性提供任何约束并不重要(此处它只是空架构{}
)。但是,此定义的存在意味着允许任何匹配的属性,而additionalProperties
禁止任何其他属性。
对于其他约束(例如你的"布尔属性必须以is
" one开头),你只需在这里添加更复杂的条目。
这个答案更侧重于如何制作通用的递归命名式架构。它已经很长了,所以如果您正在寻找有关如何表达特定约束的指导,那么将它作为一个单独的问题提出来可能更为简洁。
properties
属性这一点非常简单 - 使这些约束适用于模式的适当部分:
{
"properties": {
"properties": {"$ref": "#/definitions/propertyStyleRule"}
},
"definitions": {
"propertyStyleRule": {
"patternProperties": {
"^[a-z]+([A-Z][a-z]*)*$": {}
},
"additionalProperties": false
}
}
}
事实上,您不仅希望涵盖"properties"
内的子模式,还需要"items"
,"anyOf"
等。
这里很长,所以我省略了大部分内容,但基本上你会浏览每个可能包含模式的关键字,并通过引用根模式确保它们遵循相同的命名方案:
{
"properties": {
"properties": {"$ref": "#/definitions/propertyStyleRule"},
"additionalProperties": {"$ref": "#"},
"items": {"$ref": "#"},
"not": {"$ref": "#"},
"allOf": {"$ref": "#"},
...
},
"definitions": {
"propertyStyleRule": {
"patternProperties": {
"^[a-z]+([A-Z][a-z]*)*$": {"$ref": "#"}
},
"additionalProperties": false
}
}
}
注意:我们现在还替换了我们的{}
定义中的空架构("propertyStyleRule"
),并引用了一个根({"$ref": "#"}
}),因此properties
内的子模式也可以正确递归。
好的,这里有一个明显的问题:"not"
拥有一个架构,所以很好,但"allOf"
包含一系列架构,"items"
可以保持,"additionalProperties"
可以是布尔值。
我们可以使用不同类型进行一些奇特的切换, 或 我们只需在根模式中添加items
条目:
{
"items": {"$ref": "#"},
"properties": {
...
},
"definitions": {
"propertyStyleRule": {...}
}
}
因为我们还没有指定type
,我们的根模式实际上允许实例为objects / arrays / boolean / string / whatever - 如果实例不是对象,那么{ {1}}只是被忽略了。
类似地,除非实例是数组,否则忽略properties
- 但如果 是数组,则条目也必须遵循根模式。因此items
的值是模式还是模式数组并不重要,无论哪种方式都可以正确地进行处理。
对于一些关键字(例如"items"
或"patternProperties"
),该值不是架构,它是字符串到架构的映射,因此您无法引用根架构。对于这些,我们将定义"definitions"
,并引用它:
"schemaMap"
......你已经完成了!
我遗漏了细节,但希望它能够清楚地写出完整版本。
此外,一旦你写了一次,应该很容易适应不同的风格规则,甚至对{
"items": {"$ref": "#"},
"properties": {
"properties": {"$ref": "#/definitions/propertyStyleRule"},
"additionalProperties": {"$ref": "#"},
"items": {"$ref": "#"},
"not": {"$ref": "#"},
"allOf": {"$ref": "#"},
...
"patternProperties": {"$ref": "#/definitions/schemaMap"},
...
},
"definitions": {
"schemaMap": {
"type": "object",
"additionalProperties": {"$ref": "#"}
},
"propertyStyleRule": {...}
}
}
中的名字应用类似的约束等。如果你写了一个这样的架构,请考虑将其发布到某个地方,以便其他人可以适应它! :)