如何在python jsonschema文档中设置本地文件引用?

如何在python jsonschema文档中设置本地文件引用?,python,json,jsonschema,python-jsonschema,Python,Json,Jsonschema,Python Jsonschema,我有一套合规文件。某些文档包含对其他文档的引用(通过$ref属性)。我不希望托管这些文档,以便可以通过HTTP URI访问它们。因此,所有引用都是相对的。所有文档都位于本地文件夹结构中 如何理解如何正确使用本地文件系统加载引用的文档 例如,如果我有一个文件名为defs.json的文档,其中包含一些定义。我尝试加载引用它的不同文档,如: { "allOf": [ {"$ref":"defs.json#/definitions/basic_event"}, { "t

我有一套合规文件。某些文档包含对其他文档的引用(通过
$ref
属性)。我不希望托管这些文档,以便可以通过HTTP URI访问它们。因此,所有引用都是相对的。所有文档都位于本地文件夹结构中

如何理解如何正确使用本地文件系统加载引用的文档


例如,如果我有一个文件名为
defs.json
的文档,其中包含一些定义。我尝试加载引用它的不同文档,如:

{
  "allOf": [
    {"$ref":"defs.json#/definitions/basic_event"},
    {
      "type": "object",
      "properties": {
        "action": {
          "type": "string",
          "enum": ["page_load"]
        }
      },
      "required": ["action"]
    }
  ]
}
我收到一个错误
refresolutionorr:

我使用linux设备可能很重要



(我写这篇文章是作为问答,因为我很难弄清楚这一点。)

您必须为每个使用相对引用的模式构建一个自定义的
jsonschema.RefResolver
,并确保您的解析器知道给定模式在文件系统上的位置

比如

import os
import json
from jsonschema import Draft4Validator, RefResolver # We prefer Draft7, but jsonschema 3.0 is still in alpha as of this writing 


abs_path_to_schema = '/path/to/schema-doc-foobar.json'
with open(abs_path_to_schema, 'r') as fp:
  schema = json.load(fp)

resolver = RefResolver(
  # The key part is here where we build a custom RefResolver 
  # and tell it where *this* schema lives in the filesystem
  # Note that `file:` is for unix systems
  schema_path='file:{}'.format(abs_path_to_schema),
  schema=schema
)
Draft4Validator.check_schema(schema) # Unnecessary but a good idea
validator = Draft4Validator(schema, resolver=resolver, format_checker=None)

# Then you can...
data_to_validate = `{...}`
validator.validate(data_to_validate)

根据@chris-w提供的答案,我想用
jsonschema 3.2.0
做同样的事情,但他的答案没有完全涵盖这一点。我希望这个答案能帮助那些仍然在这个问题上寻求帮助但正在使用更新版本的软件包的人

要使用库扩展JSON模式,请执行以下操作:

  • 创建基本架构:
  • 创建扩展架构
  • 创建要根据模式测试的JSON文件
  • 为基本模式创建RefResolver和Validator,并使用它检查数据
  • 您可能需要对上述条目进行一些调整,例如不使用Draft7Validator。这应该适用于单级引用(扩展基的子级),您需要小心使用模式以及如何设置
    RefResolver
    Validator
    对象

    这里是一个练习以上内容的剪报。尝试修改
    数据
    字符串以删除所需属性之一:

    import json
    
    from jsonschema import RefResolver, Draft7Validator
    
    base = """
    {
      "$id": "base.schema.json",
      "type": "object",
      "properties": {
        "prop": {
          "type": "string"
        }
      },
      "required": ["prop"]
    }
    """
    
    extend = """
    {
      "allOf": [
        {"$ref": "base.schema.json"},
        {
          "properties": {
            "extra": {
              "type": "boolean"
            }
          },
          "required": ["extra"]
        }
      ]
    }
    """
    
    data = """
    {
    "prop": "This is the property string",
    "extra": true
    }
    """
    
    schema = json.loads(base)
    extendedSchema = json.loads(extend)
    resolver = RefResolver.from_schema(schema)
    validator = Draft7Validator(extendedSchema, resolver=resolver)
    
    jsonData = json.loads(data)
    validator.validate(jsonData)
    

    我最难弄清楚如何针对一组相互
    $ref
    的模式进行解析(我不熟悉JSON模式)。事实证明,关键是使用
    存储创建
    RefResolver
    ,这是一个从url映射到模式的
    dict
    。 基于@devin-p的答案:

    导入json
    来自jsonschema导入引用器、Draft7Validator
    base=“”
    {
    “$id”:“base.schema.json”,
    “类型”:“对象”,
    “财产”:{
    “道具”:{
    “类型”:“字符串”
    }
    },
    “必需”:[“道具”]
    }
    """
    扩展“”
    {  
    “$id”:“extend.schema.json”,
    “allOf”:[
    {“$ref”:“base.schema.json#”},
    {
    “财产”:{
    “额外”:{
    “类型”:“布尔”
    }
    },
    “必需”:[“额外”]
    }
    ]
    }
    """
    扩展_extend=“”
    {
    “$id”:“extend_extend.schema.json”,
    “allOf”:[
    {“$ref”:“extend.schema.json#”},
    {
    “财产”:{
    “附加条款2”:{
    “类型”:“布尔”
    }
    },
    “必需”:[“额外2”]
    }
    ]
    }
    """
    data=”“”
    {
    “prop”:“这是属性字符串”,
    “额外”:正确,
    “额外2”:错误
    }
    """
    schema=json.loads(基本)
    extendedSchema=json.loads(extend)
    extendedExtendSchema=json.load(extend\u extend)
    架构存储={
    架构['$id']:架构,
    extendedSchema['$id']:extendedSchema,
    extendedExtendSchema['$id']:extendedExtendSchema,
    }
    解析程序=从模式(模式,存储=模式存储)中引用解析程序
    验证器=Draft7Validator(extendedExtendSchema,解析器=解析器)
    jsonData=json.loads(数据)
    validator.validate(jsonData)
    

    上面是用
    jsonschema==3.2.0构建的

    我的方法是将所有模式片段预加载到RefResolver缓存。我创建了一个要点来说明这一点:

    EDIT-1 修复了对
    base
    架构的错误引用(
    $ref
    )。 更新示例以使用文档中的示例:

    编辑-2 正如评论中所指出的,在以下内容中,我使用了以下导入:

    from jsonschema import validate, RefResolver 
    from jsonschema.validators import validator_for
    

    这只是@Daniel回答的另一个版本——对我来说是正确的。基本上,我决定在基本模式中定义
    $schema
    。然后释放其他模式,并在实例化解析器时进行明确调用

    • 事实上,
      RefResolver.from_schema()
      获取了(1)一些模式,以及(2)一个模式存储,我不太清楚这里的顺序和“某些”模式是否相关。下面就是你看到的结构
    我有以下资料:

    base.schema.json

    {
    “$schema”:”http://json-schema.org/draft-07/schema#"
    }
    
    definitions.schema.json

    {
    “类型”:“对象”,
    “财产”:{
    “街道地址”:{“类型”:“字符串”},
    “城市”:{“类型”:“字符串”},
    “状态”:{“类型”:“字符串”}
    },
    “必需”:[“街道地址”、“城市”、“州”]
    }
    
    address.schema.json

    {
    “类型”:“对象”,
    “财产”:{
    “账单地址”:{“$ref”:“definitions.schema.json”},
    “shipping_address”:{“$ref”:“definitions.schema.json#”}
    }
    }
    
    我喜欢这种设置有两个原因:

  • 是对
    RefResolver.from_schema()
    的更干净的调用:

    base=json.load(打开('base.schema.json').read())
    definitions=json.load(打开('definitions.schema.json').read())
    schema=json.load(打开('address.schema.json').read())
    架构存储={
    base.get('$id','base.schema.json'):base,
    definitions.get('$id','definitions.schema.json'):定义,
    schema.get('$id','address.schema.json'):schema,
    }
    解析程序=从模式(基,存储=模式\u存储)中引用解析程序
    
  • 然后,我从库提供的便捷工具中获益,它为您的模式提供了最佳的
    验证工具(根据您的
    $schema
    键):

    Valida
    
    data.json
    {
      "prop": "This is the property",
      "extra": true
    }
    
    #Set up schema, resolver, and validator on the base schema
    baseSchema = json.loads(baseSchemaJSON) # Create a schema dictionary from the base JSON file
    relativeSchema = json.loads(relativeJSON) # Create a schema dictionary from the relative JSON file
    resolver = RefResolver.from_schema(baseSchema) # Creates your resolver, uses the "$id" element
    validator = Draft7Validator(relativeSchema, resolver=resolver) # Create a validator against the extended schema (but resolving to the base schema!)
    
    # Check validation!
    data = json.loads(dataJSON) # Create a dictionary from the data JSON file
    validator.validate(data)
    
    import json
    
    from jsonschema import RefResolver, Draft7Validator
    
    base = """
    {
      "$id": "base.schema.json",
      "type": "object",
      "properties": {
        "prop": {
          "type": "string"
        }
      },
      "required": ["prop"]
    }
    """
    
    extend = """
    {
      "allOf": [
        {"$ref": "base.schema.json"},
        {
          "properties": {
            "extra": {
              "type": "boolean"
            }
          },
          "required": ["extra"]
        }
      ]
    }
    """
    
    data = """
    {
    "prop": "This is the property string",
    "extra": true
    }
    """
    
    schema = json.loads(base)
    extendedSchema = json.loads(extend)
    resolver = RefResolver.from_schema(schema)
    validator = Draft7Validator(extendedSchema, resolver=resolver)
    
    jsonData = json.loads(data)
    validator.validate(jsonData)
    
    from jsonschema import validate, RefResolver 
    from jsonschema.validators import validator_for