前言
jsonschema 是一个强大的库,用于验证 JSON 数据是否符合特定的模式(Schema)。在实际应用中,你可能会遇到更复杂的 JSON 结构和验证需求。下面我将详细介绍 jsonschema 的一些高级用法,包括复杂的数据结构、自定义验证器以及如何处理嵌套的 JSON 对象。
1. 复杂的数据结构
1.1 数组验证
你可以验证数组中的每个元素是否符合特定的模式。
import json
from jsonschema import validate, ValidationError
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"ages": {
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"maximum": 120
}
}
},
"required": ["name", "ages"]
}
# 待验证的 JSON 数据
data = {
"name": "Alice",
"ages": [25, 30, 35]
}
# 验证 JSON 数据
try:
validate(instance=data, schema=schema)
print("JSON data is valid.")
except ValidationError as e:
print(f"JSON data is invalid: {e}")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
1.2 嵌套对象验证
你可以验证嵌套的对象是否符合特定的模式。
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"address": {
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"},
"zipcode": {"type": "string"}
},
"required": ["street", "city"]
}
},
"required": ["name", "address"]
}
# 待验证的 JSON 数据
data = {
"name": "Alice",
"address": {
"street": "123 Main St",
"city": "Anytown",
"zipcode": "12345"
}
}
# 验证 JSON 数据
try:
validate(instance=data, schema=schema)
print("JSON data is valid.")
except ValidationError as e:
print(f"JSON data is invalid: {e}")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
2. 自定义验证器
有时候你需要进行更复杂的验证逻辑,这时可以使用 jsonschema 的 Validator 类来创建自定义验证器。
2.1 自定义格式验证
你可以添加自定义的格式验证器,例如验证电话号码格式。
from jsonschema import Draft7Validator, FormatChecker, ValidationError
# 定义自定义格式验证器
def is_valid_phone_number(phone_number):
return phone_number.isdigit() and len(phone_number) == 10
format_checker = FormatChecker()
format_checker.checks('phone')(is_valid_phone_number)
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"phone": {"type": "string", "format": "phone"}
},
"required": ["name", "phone"]
}
# 待验证的 JSON 数据
data = {
"name": "Alice",
"phone": "1234567890"
}
# 创建 Validator 并验证 JSON 数据
validator = Draft7Validator(schema, format_checker=format_checker)
try:
validator.validate(data)
print("JSON data is valid.")
except ValidationError as e:
print(f"JSON data is invalid: {e}")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
2.2 自定义验证函数
你可以为特定属性添加自定义的验证逻辑。
from jsonschema import Draft7Validator, ValidationError
# 定义自定义验证函数
def is_even(value):
if value % 2 != 0:
raise ValidationError(f"{value} is not an even number")
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"number": {"type": "integer"}
},
"required": ["name", "number"],
"additionalProperties": False
}
# 创建 Validator 并添加自定义验证函数
validator = Draft7Validator(schema)
validator.VALIDATORS["even"] = is_even
schema["properties"]["number"]["even"] = True
# 待验证的 JSON 数据
data = {
"name": "Alice",
"number": 4
}
# 验证 JSON 数据
try:
validator.validate(data)
print("JSON data is valid.")
except ValidationError as e:
print(f"JSON data is invalid: {e}")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
3. 使用 RefResolver 进行模块化验证
对于大型项目,你可能希望将 Schema 分成多个文件,并使用引用($ref)来组合它们。RefResolver 可以帮助你管理这些引用。
3.1 模块化 Schema 文件
假设你有两个文件:person_schema.json 和 address_schema.json。
person_schema.json
{
"$id": "http://example.com/schemas/person",
"type": "object",
"properties": {
"name": {"type": "string"},
"address": {"$ref": "http://example.com/schemas/address"}
},
"required": ["name", "address"]
}
address_schema.json
{
"$id": "http://example.com/schemas/address",
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"},
"zipcode": {"type": "string"}
},
"required": ["street", "city"]
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
3.2 使用 RefResolver 进行验证
import json
from jsonschema import RefResolver, Draft7Validator, ValidationError
# 读取 Schema 文件
with open('person_schema.json') as f:
person_schema = json.load(f)
with open('address_schema.json') as f:
address_schema = json.load(f)
# 创建 RefResolver
resolver = RefResolver(
base_uri="http://example.com/schemas/",
referrer=person_schema,
store={
"http://example.com/schemas/person": person_schema,
"http://example.com/schemas/address": address_schema
}
)
# 创建 Validator
validator = Draft7Validator(person_schema, resolver=resolver)
# 待验证的 JSON 数据
data = {
"name": "Alice",
"address": {
"street": "123 Main St",
"city": "Anytown",
"zipcode": "12345"
}
}
# 验证 JSON 数据
try:
validator.validate(data)
print("JSON data is valid.")
except ValidationError as e:
print(f"JSON data is invalid: {e}")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
4. 使用 jsonschema 进行数据转换
虽然 jsonschema 主要用于验证,但你可以结合其他库(如 voluptuous 或 marshmallow)来进行数据转换和验证。
4.1 结合 voluptuous 进行数据转换
voluptuous 是一个轻量级的数据验证和转换库,可以与 jsonschema 结合使用。
import json
import voluptuous as vol
from jsonschema import validate, ValidationError
# 定义 JSON Schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "age"]
}
# 定义 Voluptuous Schema
vol_schema = vol.Schema({
vol.Required('name'): str,
vol.Required('age'): int,
vol.Optional('email'): vol.Email()
})
# 待验证的 JSON 数据
data = {
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
# 验证 JSON 数据
try:
validate(instance=data, schema=schema)
transformed_data = vol_schema(data)
print("JSON data is valid and transformed:", transformed_data)
except (ValidationError, vol.Invalid) as e:
print(f"JSON data is invalid: {e}")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.