执行"风格" JSON Schema文件中的规则?

时间:2014-06-05 17:11:04

标签: json coding-style naming-conventions jsonschema

我正在考虑将JSON Schemas用于即将开展的项目,并寻找一种方法来验证JSON Schema文件中的命名约定/样式和一致性规则。与StyleCopCheckstyle有些相似。

使用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模式文件并编写规则?

1 个答案:

答案 0 :(得分:1)

完全有可能编写一个元模式来对您的模式强制执行此约束。让我们一步一步地构建它:

1。约束属性名称

关键部分是使用patternProperties指定允许的属性名称,additionalProperties禁止其他任何属性:

{
    "patternProperties": {
        "^[a-z]+([A-Z][a-z]*)*$": {}
    },
    "additionalProperties": false
}

(对于这个例子,我使用了正则表达式^[a-z]+([A-Z][a-z]*)*$来检测仅字母的lowerCamelCase)

请注意,是否为适当命名的属性提供任何约束并不重要(此处它只是空架构{})。但是,此定义的存在意味着允许任何匹配的属性,而additionalProperties禁止任何其他属性。

发烧友约束

对于其他约束(例如你的"布尔属性必须以is" one开头),你只需在这里添加更复杂的条目。

这个答案更侧重于如何制作通用的递归命名式架构。它已经很长了,所以如果您正在寻找有关如何表达特定约束的指导,那么将它作为一个单独的问题提出来可能更为简洁。

2。应用于properties属性

这一点非常简单 - 使这些约束适用于模式的适当部分:

{
    "properties": {
        "properties": {"$ref": "#/definitions/propertyStyleRule"}
    },
    "definitions": {
        "propertyStyleRule": {
            "patternProperties": {
                "^[a-z]+([A-Z][a-z]*)*$": {}
            },
            "additionalProperties": false
        }
    }
}

3。使其递归

事实上,您不仅希望涵盖"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内的子模式也可以正确递归。

4。坚持下去,其中一些关键字可以是数组,也可以是布尔值,或者......

好的,这里有一个明显的问题:"not"拥有一个架构,所以很好,但"allOf"包含一系列架构,"items"可以保持,"additionalProperties"可以是布尔值。

我们可以使用不同类型进行一些奇特的切换, 我们只需在根模式中添加items条目:

{
    "items": {"$ref": "#"},
    "properties": {
        ...
    },
    "definitions": {
        "propertyStyleRule": {...}
    }
}

因为我们还没有指定type,我们的根模式实际上允许实例为objects / arrays / boolean / string / whatever - 如果实例不是对象,那么{ {1}}只是被忽略了。

类似地,除非实例是数组,否则忽略properties - 但如果 是数组,则条目也必须遵循根模式。因此items的值是模式还是模式数组并不重要,无论哪种方式都可以正确地进行处理。

5。架构映射

对于一些关键字(例如"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": {...} } } 中的名字应用类似的约束等。如果你写了一个这样的架构,请考虑将其发布到某个地方,以便其他人可以适应它! :)