我尝试使用Python 3中的jsonschema
模块递归验证模板JSON模式的自定义JSON模式。
自定义JSON如下所示:
{
"endpoint": "rfc",
"filter_by": ["change_ref", "change_i"],
"expression": [
{
"field": "first_name",
"operator": "EQ",
"value": "O'Neil"
},
"AND",
[
{
"field": "last_name",
"operator": "NEQ",
"value": "Smith"
},
"OR",
{
"field": "middle_name",
"operator": "EQ",
"value": "Sam"
}
]
],
"limit_results_to": "2"
}
通过添加多个AND
和OR
s =>可以进一步推广上述内容。我的问题与递归有关。
我尝试验证此架构的模板位于以下代码段中:
import json
import jsonschema
def get_data(file):
with open(file) as data_file:
return json.load(data_file)
def json_schema_is_valid():
data = get_data("other.json")
valid_schema = {
"type": "object",
"required": ["endpoint", "filter_by", "expression", "limit_results_to"],
"properties": {
"endpoint": {
"type": "string",
"additionalProperties": False
},
"filter_by": {
"type": ["string", "array"],
"additionalProperties": False
},
"limit_results_to": {
"type": "string",
"additionalProperties": False
},
"expression": {
"type": "array",
"properties": {
"field": {
"type": "string",
"additionalProperties": False
},
"operator": {
"type": "string",
"additionalProperties": False
},
"value": {
"type": "string",
"additionalProperties": False
}
},
"required": ["field", "operator", "value"]
}
}
}
return jsonschema.validate(data, valid_schema)
if __name__ == '__main__':
print(json_schema_is_valid())
现在,出现了一些错误,因为当我运行上面的代码时,我得到的None
可能(不)没问题。当我尝试修改type
中property
的某些不允许的内容时,我不会得到任何感知。我的模板中有什么问题吗? Here,看起来表达式属性未被解析。更多,我阅读here我可以使用'$ref': '#'
递归验证我的自定义JSON架构,但我还不太了解如何使用它。有人可以给我一些提示吗?
答案 0 :(得分:0)
您的架构看起来有效,不包括递归部分。查看GitHub上jsonschema.validate
的源代码,我们可以看到代码没有return
。所以我认为可以安全地假设你验证的方式是使用类似的东西:
try:
jsonschema.validate(json_data, schema)
except ...:
print('invalid json')
else:
print('valid json')
要创建递归,您应该制作两个定义。我从Recursive JSON Schema找到了如何做到这一点。你只需要做几个定义。首先是你的正常比较。这几乎只是将您当前的定义移到它自己的定义中。
{
"definitions": {
"comparison": {
"type": "object",
"additionalProperties": false,
"properties": {
"field": {
"type": "string"
},
"operator": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": ["field", "operator", "value"]
}
}
}
执行递归布尔比较要困难一些。我不知道如何将数组限制为三个项目,其中第二个是不同的类型,所以我选择使用一个对象,它有三个明确定义的项目。第一个和最后一个项目也应该具有相同的类型,以便您可以进行(a and b) or (c and d)
之类的比较。所以我得到了以下架构:
{
"definitions": {
"comparison": {
"type": "object",
"additionalProperties": false,
"properties": {
"field": {
"type": "string"
},
"operator": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": ["field", "operator", "value"]
},
"booleanComparison": {
"type": "object",
"additionalProperties": false,
"properties": {
"item1": {
"type": "object",
"oneOf": [
{"$ref": "#/definitions/comparison"},
{"$ref": "#/definitions/booleanComparison"}
]
},
"operator": {
"type": "string"
},
"item2": {
"type": "object",
"oneOf": [
{"$ref": "#/definitions/comparison"},
{"$ref": "#/definitions/booleanComparison"}
]
}
},
"required": ["item1", "operator", "item2"]
}
},
"type": "object",
"properties": {
"endpoint": {
"type": "string"
},
"filter_by": {
"type": ["string", "array"]
},
"limit_results_to": {
"type": "string",
"additionalProperties": false
},
"expression": {
"type": "object",
"oneOf": [
{"$ref": "#/definitions/comparison"},
{"$ref": "#/definitions/booleanComparison"}
]
}
},
"required": ["endpoint", "filter_by", "expression", "limit_results_to"]
}
其中说以下内容有效:
{
"endpoint": "rfc",
"filter_by": ["change_ref", "change_i"],
"limit_results_to": "2",
"expression": {
"item1": {
"field": "first_name",
"operator": "EQ",
"value": "O'Neil"
},
"operator": "AND",
"item2": {
"item1": {
"field": "last_name",
"operator": "NEQ",
"value": "Smith"
},
"operator": "OR",
"item2": {
"field": "middle_name",
"operator": "EQ",
"value": "Sam"
}
}
}
}
但是,如果您将"value": "Sam"
更改为"value": true
,则说它无效,因为它的类型错误。所以它似乎递归地工作。