【问题标题】:Json - recursively validate schema with PythonJson - 使用 Python 递归验证模式
【发布时间】:2018-02-05 16:52:18
【问题描述】:

我正在尝试使用 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"
} 

以上可以通过添加多个ANDs 和ORs 来进一步概括 => 我的问题与递归有关。

我尝试验证此架构的模板位于以下代码段中:

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,这可能(不是)没问题。当我试图以不允许的方式修改 propertytype 时,我没有得到任何异常。我的模板有问题吗? Here,看起来表达式属性没有被解析。此外,我阅读了here,我可以使我的模板使用'$ref': '#' 递归地验证我的自定义 JSON 模式,但我不太了解如何使用它。有人可以给我一些提示吗?

【问题讨论】:

    标签: python json python-3.x jsonschema


    【解决方案1】:

    您的架构看起来可以工作,但不包括递归部分。在 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 则无效,因为它是错误的类型。所以它似乎可以递归地按预期工作。

    【讨论】:

      猜你喜欢
      • 2014-08-30
      • 1970-01-01
      • 1970-01-01
      • 2020-03-21
      • 2014-09-19
      • 2019-12-14
      • 2022-01-02
      • 1970-01-01
      • 2015-07-18
      相关资源
      最近更新 更多