如何为Python jsonschema多组anyOf必填规则设置自定义错误信息?
自定义JSON Schema校验错误提示
问题背景
需要校验JSON必须同时满足两个条件:至少包含第一组属性(a、b、c)中的一个,且至少包含第二组属性(x、y、z)中的一个。使用allOf嵌套anyOf的Schema逻辑正确,但校验空JSON{}时,仅得到通用错误{} is not valid under any of the given schemas,希望替换为更具体的提示,比如必须包含'a'、'b'、'c'中的至少一个和必须包含'x'、'y'、'z'中的至少一个。
原Schema如下:
{ "type": "object", "properties": { "a": {"type": "string"}, "b": {"type": "string"}, "c": {"type": "string"}, "x": {"type": "string"}, "y": {"type": "string"}, "z": {"type": "string"} }, "allOf": [ {"anyOf": [ {"required": ["a"]}, {"required": ["b"]}, {"required": ["c"]} ]}, {"anyOf": [ {"required": ["x"]}, {"required": ["y"]}, {"required": ["z"]} ]} ] }
解决方案
Python的jsonschema库默认不支持直接在Schema中定义自定义错误信息,但可以通过自定义错误解析逻辑生成友好提示,以下是两种实用方法:
方法1:给Schema添加描述字段,直接提取提示
在每个anyOf块中加入自定义description字段,作为错误提示的直接来源,修改后的Schema如下:
{ "type": "object", "properties": { "a": {"type": "string"}, "b": {"type": "string"}, "c": {"type": "string"}, "x": {"type": "string"}, "y": {"type": "string"}, "z": {"type": "string"} }, "allOf": [ { "description": "必须包含'a'、'b'、'c'中的至少一个", "anyOf": [ {"required": ["a"]}, {"required": ["b"]}, {"required": ["c"]} ] }, { "description": "必须包含'x'、'y'、'z'中的至少一个", "anyOf": [ {"required": ["x"]}, {"required": ["y"]}, {"required": ["z"]} ] } ] }
然后编写校验函数,捕获错误时提取description:
from jsonschema import validate, ValidationError def validate_json(instance, schema): try: validate(instance=instance, schema=schema) return {"valid": True, "errors": []} except ValidationError as e: errors = [] # 遍历allOf下的每个失败约束 for err in e.context: if err.schema.get("description"): errors.append(err.schema["description"]) else: errors.append(err.message) return {"valid": False, "errors": errors} # 测试空JSON test_instance = {} result = validate_json(test_instance, schema) print(result) # 输出:{"valid": False, "errors": ["必须包含'a'、'b'、'c'中的至少一个", "必须包含'x'、'y'、'z'中的至少一个"]}
方法2:通过错误上下文判断属性组生成提示
如果不想修改Schema,可以通过解析错误的schema_path和schema属性,判断失败的是哪一组约束,生成对应提示:
from jsonschema import validate, ValidationError def validate_json(instance, schema): try: validate(instance=instance, schema=schema) return {"valid": True, "errors": []} except ValidationError as e: errors = [] for err in e.context: # 判断当前失败的anyOf属于哪一组属性 first_group = {"a", "b", "c"} second_group = {"x", "y", "z"} # 取anyOf下第一个required的属性作为分组标识 sample_required = err.schema.get("anyOf", [])[0].get("required", []) if sample_required and first_group & set(sample_required): errors.append("必须包含'a'、'b'、'c'中的至少一个") elif sample_required and second_group & set(sample_required): errors.append("必须包含'x'、'y'、'z'中的至少一个") else: errors.append(err.message) return {"valid": False, "errors": errors} # 测试空JSON test_instance = {} result = validate_json(test_instance, schema) print(result) # 输出:{"valid": False, "errors": ["必须包含'a'、'b'、'c'中的至少一个", "必须包含'x'、'y'、'z'中的至少一个"]}
说明
- 方法1更简洁易维护,通过在Schema中嵌入提示信息,无需硬编码属性组判断。
- 若需要处理更复杂的校验场景,可以结合
schema_path和instance_path进一步细化错误内容。
内容的提问来源于stack exchange,提问作者matetam
相关产品推荐
相关产品推荐

