【问题标题】:JSON schema property has wider scope than expectedJSON 模式属性的范围比预期的要宽
【发布时间】:2017-07-21 14:17:07
【问题描述】:

我有以下 JSON 模式 (testschema.json),我正在 Python3 中进行测试。 我不断收到属性 "alpha" 的验证错误,我尝试以各种方式声明该属性均无济于事。

{
    "id": "testschema",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "test schema",

    "type": "object",
    "properties": {


        "traffic_parameters": {

            "properties": {

                "test_type": {

                    "type": "string",
                    "enum": ["AA", "BB"]
                },

                "capacity": {

                    "oneOf": [
                        {
                            "properties": {

                                "min_percentage": {

                                    "type": "integer",
                                    "minimum" : 1,
                                    "maximum" : 150,
                                    "additionalProperties": false
                                },

                                "max_percentage": {

                                    "type": "integer",
                                    "minimum" : 1,
                                    "maximum" : 150,
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "percentage_range": {

                                    "type": "array",
                                    "minItems": 1,
                                    "maxItems": 10,
                                    "items": {

                                        "type": "integer"
                                    },

                                   "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        }                    
                    ]
                }
            },

            "additionalProperties": false
        },


        "alpha": {

            "properties": {

                "beta": {

                    "oneOf": [
                        {
                            "properties": {

                                "AA": {

                                    "a":   [90, 95],
                                    "b":   [4, 8],
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "BB": {

                                    "a":   [100],
                                    "b":   [0],
                                    "c": [0],
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "CC": {

                                    "a":   [50],
                                    "b":   [50],
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false
                        },

                        {
                            "properties": {

                                "DD": {

                                    "a":   [0],
                                    "b":   [0],
                                    "c": [100],
                                    "additionalProperties": false  
                                }
                            },

                            "additionalProperties": false
                        }
                    ]
                }
            },

            "additionalProperties": false
        }
    },

    "required": ["traffic_parameters", "alpha"]
}

这是使用此架构的测试 JSON (test.json)。

{
    "traffic_parameters": {

        "test_type": "BB",

        "capacity": {

            "percentage_range": [1,2,3,4,5,6]
        }
     },

    "alpha": {

        "beta": "AA"
    }
}

当我使用 Python3 jsonschema 模块验证这一点时

with open("testschema.json") as schema_file:
    test_schema = json.load(schema_file)
schema_file.close()

with open("test.json") as json_file:
    test_json = json.load(json_file)
json_file.close()

validate(test_json, test_schema)

我在alpha 属性上收到一个错误,该属性的结构与traffic_parameters 相似,但没有错误。

jsonschema.exceptions.ValidationError: 'AA' is valid under each of {'properties': {'BB': ...

这是输出

E
======================================================================
ERROR: test_valid__JSON_against_schema (__main__.SchemaTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 35, in test_valid__JSON_against_schema
    validate(test_json, test_schema)
  File "/local/tools/PACKAGES/pyhton3/lib/python3.6/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/local/tools/PACKAGES/pyhton3/lib/python3.6/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: 'AA' is valid under each of {'properties': {'BB': {'a': [100], 'b': [0], 'c': [0], 'additionalProperties': False}}, 'additionalProperties': False}, {'properties': {'CC': {'a': [50], 'b': [50], 'additionalProperties': False}}, 'additionalProperties': False}, {'properties': {'DD': {'a': [0], 'b': [0], 'c': [100], 'additionalProperties': False}}, 'additionalProperties': False}, {'properties': {'AA': {'a': [90, 95], 'b': [4, 8], 'additionalProperties': False}}, 'additionalProperties': False}

Failed validating 'oneOf' in schema['properties']['alpha']['properties']['beta']:
    {'oneOf': [{'additionalProperties': False,
                'properties': {'AA': {'a': [90, 95],
                                      'additionalProperties': False,
                                      'b': [4, 8]}}},
               {'additionalProperties': False,
                'properties': {'BB': {'a': [100],
                                      'additionalProperties': False,
                                      'b': [0],
                                      'c': [0]}}},
               {'additionalProperties': False,
                'properties': {'CC': {'a': [50],
                                      'additionalProperties': False,
                                      'b': [50]}}},
               {'additionalProperties': False,
                'properties': {'DD': {'a': [0],
                                      'additionalProperties': False,
                                      'b': [0],
                                      'c': [100]}}}]}

On instance['alpha']['beta']:
    'AA'

----------------------------------------------------------------------
Ran 1 test in 0.007s

FAILED (errors=1)

有谁知道这是为什么以及如何解决它?

谢谢。

【问题讨论】:

    标签: python json jsonschema


    【解决方案1】:

    我将把架构缩短到足以重现验证失败的程度:

    {
        "id": "testschema",
        "$schema": "http://json-schema.org/draft-04/schema#",
        "description": "test schema",
        "type": "object",
        "properties": {
            "alpha": {
                "properties": {
                    "beta": {
                        "oneOf": [
                            {
                                "properties": {
                                    "AA": {
                                        "a":   [90, 95],
                                        "b":   [4, 8],
                                        "additionalProperties": false
                                    }
                                },
                                "additionalProperties": false
                            },
                            {
                                "properties": {
                                    "BB": {
                                        "a":   [100],
                                        "b":   [0],
                                        "c": [0],
                                        "additionalProperties": false
                                    }
                                },
                                "additionalProperties": false
                            }
                        ]
                    }
                },
                "additionalProperties": false
            }
        },
        "required": [ "alpha" ]
    }
    

    该错误表明无法验证oneOf 约束,因为"AA" 成功验证了oneOf 中列出的每个架构,并且oneOf 要求它必须匹配一个且只有一个。

    为什么"AA" 会针对每个架构进行验证?根本原因是架构没有为oneOf 中列出的每个架构指定"type" 信息。正如here 所解释的,如果没有为模式指定"type",则任何类型的任何有效JSON 都可能与该模式匹配。为了解决这个问题,我们需要添加缺少的"type" 约束。

    通过查看架构和 JSON 示例,我不确定您想要实现什么。该架构似乎将 "AA""BB" 等描述为嵌套对象,但 JSON 示例似乎表明 "beta" 只需要映射到像 "AA" 这样的字符串值。

    如果 JSON 样本是正确的信息来源,您可以使用这样的架构解决问题。

    schema = json.loads('''
    {
        "id": "testschema",
        "$schema": "http://json-schema.org/draft-04/schema#",
        "description": "test schema",
        "type": "object",
        "properties": {
            "alpha": {
                "type": "object",
                "properties": {
                    "beta": {
                        "type": "string",
                        "enum": [ "AA", "BB", "CC", "DD" ]
                    }
                },
                "additionalProperties": false
            }
        },
        "required": [ "alpha" ]
    }
    ''')
    
    # valid
    validate(json.loads('''
    {
        "alpha": {
            "beta": "AA"
        }
    }
    '''), schema)
    
    # valid
    validate(json.loads('''
    {
        "alpha": {
            "beta": "BB"
        }
    }
    '''), schema)
    
    # invalid
    validate(json.loads('''
    {
        "alpha": {
            "beta": "ZZ"
        }
    }
    '''), schema)
    
    Traceback (most recent call last):
      File "<stdin>", line 7, in <module>
      File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 541, in validate
        cls(schema, *args, **kwargs).validate(instance)
      File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 130, in validate
        raise error
    jsonschema.exceptions.ValidationError: u'ZZ' is not one of [u'AA', u'BB', u'CC', u'DD']
    
    Failed validating u'enum' in schema[u'properties'][u'alpha'][u'properties'][u'beta']:
        {u'enum': [u'AA', u'BB', u'CC', u'DD'], u'type': u'string'}
    
    On instance[u'alpha'][u'beta']:
        u'ZZ'
    

    OTOH,如果您的目标是让 "AA""BB" 等成为子对象,那么您可以通过将架构更改为类似这样的方式来修复它。

    schema = json.loads('''
    {
        "id": "testschema",
        "$schema": "http://json-schema.org/draft-04/schema#",
        "description": "test schema",
        "type": "object",
        "properties": {
            "alpha": {
                "type": "object",
                "properties": {
                    "beta": {
                        "oneOf": [
                            {
                                "type": "object",
                                "properties": {
                                    "AA": {
                                        "type": "object",
                                        "properties": {
                                            "a": {
                                                "type": "array"
                                            }
                                        }
                                    }
                                },
                                "additionalProperties": false
                            },
                            {
                                "type": "object",
                                "properties": {
                                    "BB": {
                                        "type": "object",
                                        "properties": {
                                            "b": {
                                                "type": "array"
                                            }
                                        }
                                    }
                                },
                                "additionalProperties": false
                            }
                        ]
                    }
                },
                "additionalProperties": false
            }
        },
        "required": [ "alpha" ]
    }
    ''')
    
    # valid
    validate(json.loads('''
    {
        "alpha": {
            "beta": {
                "AA": {
                    "a": [ 1 ]
                }
            }
        }
    }
    '''), schema)
    
    # valid
    validate(json.loads('''
    {
        "alpha": {
            "beta": {
                "BB": {
                    "b": [ 1 ]
                }
            }
        }
    }
    '''), schema)
    
    # invalid
    validate(json.loads('''
    {
        "alpha": {
            "beta": {
                "ZZ": {
                    "z": [ 1 ]
                }
            }
        }
    }
    '''), schema)
    Traceback (most recent call last):
      File "<stdin>", line 11, in <module>
      File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 541, in validate
        cls(schema, *args, **kwargs).validate(instance)
      File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 130, in validate
        raise error
    jsonschema.exceptions.ValidationError: {u'ZZ': {u'z': [1]}} is not valid under any of the given schemas
    
    Failed validating u'oneOf' in schema[u'properties'][u'alpha'][u'properties'][u'beta']:
        {u'oneOf': [{u'additionalProperties': False,
                     u'properties': {u'AA': {u'properties': {u'a': {u'type': u'array'}},
                                             u'type': u'object'}},
                     u'type': u'object'},
                    {u'additionalProperties': False,
                     u'properties': {u'BB': {u'properties': {u'b': {u'type': u'array'}},
                                             u'type': u'object'}},
                     u'type': u'object'}]}
    
    On instance[u'alpha'][u'beta']:
        {u'ZZ': {u'z': [1]}}
    
    # invalid
    validate(json.loads('''
    {
        "alpha": {
            "beta": {
                "AA": {
                    "a": [ 1 ]
                },
                "BB": {
                    "b": [ 1 ]
                }
            }
        }
    }
    '''), schema)
    
    Traceback (most recent call last):
      File "<stdin>", line 14, in <module>
      File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 541, in validate
        cls(schema, *args, **kwargs).validate(instance)
      File "/Library/Python/2.7/site-packages/jsonschema/validators.py", line 130, in validate
        raise error
    jsonschema.exceptions.ValidationError: {u'AA': {u'a': [1]}, u'BB': {u'b': [1]}} is not valid under any of the given schemas
    
    Failed validating u'oneOf' in schema[u'properties'][u'alpha'][u'properties'][u'beta']:
        {u'oneOf': [{u'additionalProperties': False,
                     u'properties': {u'AA': {u'properties': {u'a': {u'type': u'array'}},
                                             u'type': u'object'}},
                     u'type': u'object'},
                    {u'additionalProperties': False,
                     u'properties': {u'BB': {u'properties': {u'b': {u'type': u'array'}},
                                             u'type': u'object'}},
                     u'type': u'object'}]}
    
    On instance[u'alpha'][u'beta']:
        {u'AA': {u'a': [1]}, u'BB': {u'b': [1]}}
    

    无论哪种方式,重要的是确保在必要时指定"type" 信息。

    【讨论】:

    • 感谢我所需要的。我还想将架构设置为“a”和“b”中的每一个的某些固定值,以便用户可以选择一组。我已经这样做了; "items": { "spot": [90, 95], "wide": [4, 8], "global": [0.2, 0.6] } 我认为我的主要困惑是什么是对象。但是您提供的链接有帮助,再次感谢。
    • 例如,如果我有 "number_of_scripts": { "type": "integer", "minimum" : 1, "maximum" : 200, "additionalProperties": false } 你会建议添加“ type": "object" 和 "properties" 或者这样就足够了?
    • 我已经发布了我想要做的第二部分作为一个单独的问题; stackoverflow.com/questions/45281533/…
    猜你喜欢
    • 2015-08-08
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    相关资源
    最近更新 更多