验证IP地址的JSON Schema无法正常工作

时间:2013-12-21 15:02:39

标签: python ip-address jsonschema

无法在一个dict中验证IP地址,文件API.json如下:

{
"$schema": "http://json-schema.org/draft-03/schema#",
"title": "test",
"type": "object",
"properties": {
    "type": {"enum": ["spice", "vnc"]},
    "listen": {
        "type": "string",
        "oneOf": [
            {"format": "ipv4"},
            {"format": "ipv6"}
        ]
    }
},
"additionalProperties": false
}

代码如下:

from jsonschema import Draft3Validator, ValidationError, FormatChecker
import json

if __name__ == '__main__':
    graphics1 = {'type': 'spice', 'listen': '0.0.0.0'}
    graphics2 = {'type': 'vnc', 'listen': '0.0.0.0'}
    graphics3 = {'type': 'abc', 'listen': '0.0.0.0'}
    graphics4 = {'type': 'vnc', 'listen': '777.485.999'}
    graphics5 = {'type': 'vnc', 'listen': 'fe00::0'}
    graphics6 = {'type': 'vnc', 'listen': 'def'}
    graphics7 = {'type': 'vnc', 'listen': 'fe00::0abcdefdefs'}
    s = json.load(open('API.json'))
    validator = Draft3Validator(s, format_checker=FormatChecker())
    for x in range(1, 8):
        try:
            graphics = locals().get('graphics'+str(x))
            validator.validate(graphics)
        except ValidationError:
            print('; '.join(e.message for e in validator.iter_errors(graphics)))

印刷品是这些:

'abc' is not one of [u'spice', u'vnc']

显然,'777.485.999','def'和'fe00 :: 0abcdefdefs'不是ip地址,但测试脚本不会发出警告。 我找到了一个文档(http://tools.ietf.org/html/draft-zyp-json-schema-03),它说的是'ip-address',但不是'ipv4',但它也不起作用。

[编辑]: 我已经为Draft3Validator添加了FormatChecker(),但它仍然无效。但是当我尝试时,Draft4Validator还可以。在doc中,我没有发现Draft3Valdator在任何地方都不支持format / ip-address,它应该可以工作。

4 个答案:

答案 0 :(得分:4)

知道了,这不是因为Draft3Validator不支持“format / ip-address”,而是“oneOf”,“allOf”,“anyOf”和“not”。所以API.json应该是:

{
"$schema": "http://json-schema.org/draft-03/schema#",
"title": "test",
"type": "object",
"properties": {
    "type": {"enum": ["spice", "vnc"]},
    "listen": {
        "type": "string",
        "format": "ip-address"
    }
},   
"additionalProperties": false
}

请参阅http://json-schema.org/draft-03/schema#http://json-schema.org/draft-04/schema#

答案 1 :(得分:3)

查看docs

格式验证是可选的,您需要格式检查才能启用它。

答案 2 :(得分:0)

如果您使用草稿4(http://json-schema.org/draft-04/schema#),我注意到的另一件事是它想要

"format": "ip-address" 

进行验证(如果您提供)

"format": "ipv4"

..它根本无法验证。

答案 3 :(得分:0)

document中提到了使用格式检查器的正确方法。[朱利安(Julian)已经提到过]

from jsonschema import Draft3Validator, ValidationError, draft3_format_checker

my_schema = {
"$schema": "http://json-schema.org/draft-03/schema#",
"title": "test",
  "type": "object",
  "properties": {
    "listen": {
        "type": "string",
        "format": 'ip-address'
    },
    "type": {"enum": ["spice", "vnc"]}
},
"additionalProperties": False
}

if __name__ == '__main__':
    graphics1 = {'type': 'spice', 'listen': 'def'}
    graphics2 = {'type': 'vnc', 'listen': '127.0.0.1'}

    validator = Draft3Validator(my_schema, format_checker=draft3_format_checker)
    for x in range(1, 3):
        try:
            graphics = locals().get('graphics'+str(x))
            validator.validate(graphics)
        except ValidationError:
            print('; '.join(e.message for e in validator.iter_errors(graphics)))

输出:

'def' is not a 'ip-address'

接下来,当您使用format时,您可以只使用format关键字,而没有type关键字。来源请看此docdoc和format部分的示例,

my_schema = {
"$schema": "http://json-schema.org/draft-03/schema#",
"title": "test",
  "type": "object",
  "properties": {
    "listen": {
        "format": 'ip-address'
    },
    "type": {"enum": ["spice", "vnc"]}
},
"additionalProperties": False
}

从您的问题来看,您似乎正在尝试同时检查IPv4和IPv6,但如果使用模式format: 'ip-address,则仅IPv4会得到验证。

from jsonschema import Draft3Validator, ValidationError, draft3_format_checker

my_schema = {
"$schema": "http://json-schema.org/draft-03/schema#",
"title": "test",
  "type": "object",
  "properties": {
    "listen": {
        "format": 'ip-address'
    },
    "type": {"enum": ["spice", "vnc"]}
},
"additionalProperties": False
}

if __name__ == '__main__':
    graphics1 = {'type': 'spice', 'listen': 'def'}
    graphics2 = {'type': 'vnc', 'listen': '127.0.0.1'}
    graphics3 = {'type': 'vnc', 'listen': '::1'}  # IPV6 localhost

    validator = Draft3Validator(my_schema, format_checker=draft3_format_checker)
    for x in range(1, 4):
        try:
            graphics = locals().get('graphics'+str(x))
            validator.validate(graphics)
        except ValidationError:
            print('; '.join(e.message for e in validator.iter_errors(graphics)))

输出:

'def' is not a 'ip-address'
'::1' is not a 'ip-address'

现在,如果您想同时使用Draft7检查IPv4和IPv6(由于问题很旧,而Draft7的新问题也有很多其他选择)。这是修改后的代码,可同时处理IPv4 / v6错误。

from jsonschema import draft7_format_checker, Draft7Validator

my_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "test",
  "type": "object",
  "properties": {
    "listen": {
        'oneOf': [
                    {"format": 'ipv4'},
                    {"format": 'ipv6'},
                ],
    },
    "type": {"enum": ["spice", "vnc"]}
},
"additionalProperties": False
}

if __name__ == '__main__':
    test_list = [{'type': 'spice', 'listen': 'def'}, {'type': 'vnc', 'listen': '127.0.0.1'},{'type': 'vnc', 'listen': '::1'}]

    validator = Draft7Validator(my_schema, format_checker=draft7_format_checker)
    for my_json in test_list:
        errors = validator.iter_errors(my_json)
        for i, error in enumerate(errors):
            print(error.message)

        # # If you want to see more detail cause of each error use this
        # # the ValidationError.context attribute can be used to see the sub-errors which caused the failure
        # for i, error in enumerate(errors):
        #     for suberror in sorted(error.context, key=lambda e: e.schema_path):
        #         print(list(suberror.relative_schema_path), suberror.message, sep=", ")

输出:

'def' is not valid under any of the given schemas

和详细输出的样本输出(在上面的代码段中已注释)

[0, 'format'], 'def' is not a 'ipv4'
[1, 'format'], 'def' is not a 'ipv6'

error.context:如果错误是由子方案中的错误引起的,则该属性中将提供子方案中的错误列表。这些错误的schema_path和路径将相对于父错误。 参考:https://python-jsonschema.readthedocs.io/en/stable/errors/