Python 中 jsonschema 深度運用
前言
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 嵌套對象驗證
你可以驗證嵌套的對象是否符合特定的模式。
# 定義 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}")
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}")
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}")
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"]
}
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}")
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}")