JSON 架构 属性 的范围比预期的要广

JSON schema property has wider scope than expected

我在 Python3 中测试了以下 JSON 架构 (testschema.json)。 我一直收到 属性 "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)

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

谢谢。

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

{
    "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" 在必要时指定信息。