【问题标题】:JSON Schema validating ip-address is not working验证 IP 地址的 JSON 模式不起作用
【发布时间】:2014-01-10 07:11:12
【问题描述】:

验证一个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 地址,但测试脚本不会给出关于它们的警告。 我找到了一个文档(https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-03),它说的是“ip-address”,但不是“ipv4”,但它也不起作用。

[编辑]: 我已经为 Draft3Validator 添加了 FormatChecker(),但它仍然无法正常工作。但正如我所尝试的,Draft4Validator 没问题。在文档中,我没有发现 Draft3Valdator 在任何地方都不支持格式/IP 地址,它应该可以工作。

【问题讨论】:

  • 呃,你为什么不使用列表而不是这个可怕的locals() hack 和不同的变量?!
  • 您具体使用的是哪个工具? format 的验证是可选的,但大多数工具允许您为特定格式提供扩展/自定义验证。

标签: python ip-address jsonschema


【解决方案1】:

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 关键字。来源查看此doc 中的示例和此doc 的格式部分,

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

和详细输出的示例输出(在上面的sn-p中注释)

[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/

【讨论】:

    【解决方案2】:

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

    "format": "ip-address" 
    

    如果你给它做它的验证

    "format": "ipv4"
    

    ..它根本不验证。

    【讨论】:

      【解决方案3】:

      知道了,不是因为 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#

      【讨论】:

        【解决方案4】:

        查看docs

        格式验证是可选的,您需要一个格式检查器来启用它。

        【讨论】:

        • 谢谢你,朱利安。你的回答很有帮助。
        猜你喜欢
        • 2018-09-16
        • 2016-06-06
        • 1970-01-01
        • 2016-01-30
        • 1970-01-01
        • 2012-02-29
        • 1970-01-01
        • 2012-04-17
        • 2010-12-02
        相关资源
        最近更新 更多