Json - 使用 Python 递归验证模式
Json - recursively validate schema with Python
我正在尝试使用 Python 中的 jsonschema
模块针对模板 JSON 模式递归验证自定义 JSON 模式 3.
自定义 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
s 和 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
这可能(不是)没问题。当我试图在不允许的情况下修改 property
的 type
时,我没有得到任何异常。我的模板有问题吗? Here, it looks like the expression properties are not parsed. More, I read here 我可以使我的模板使用 '$ref': '#'
递归验证我的自定义 JSON 模式,但我不太明白如何使用它。有人可以给我一些提示吗?
您的模式看起来有效,但不包括递归部分。查看 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
是无效的,因为它是错误的类型。所以它似乎递归地按预期工作。
我正在尝试使用 Python 中的 jsonschema
模块针对模板 JSON 模式递归验证自定义 JSON 模式 3.
自定义 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
s 和 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
这可能(不是)没问题。当我试图在不允许的情况下修改 property
的 type
时,我没有得到任何异常。我的模板有问题吗? Here, it looks like the expression properties are not parsed. More, I read here 我可以使我的模板使用 '$ref': '#'
递归验证我的自定义 JSON 模式,但我不太明白如何使用它。有人可以给我一些提示吗?
您的模式看起来有效,但不包括递归部分。查看 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
是无效的,因为它是错误的类型。所以它似乎递归地按预期工作。