如何为Python的ElementTree创建自定义Pydantic类型
解决Pydantic自定义ElementTree.Element类型的问题
问题出在ElementTree.Element并非Pydantic原生支持的类型,直接用Annotated无法让Pydantic自动识别其转换逻辑。以下是两种可行的实现方案:
方案一:使用Annotated + 前置验证器
通过BeforeValidator指定自定义解析函数,实现字符串到ET.Element的转换,并处理XML解析错误:
import xml.etree.ElementTree as ET from pydantic import BaseModel, BeforeValidator, ValidationError, Annotated def parse_xml(xml_str: str) -> ET.Element: try: return ET.fromstring(xml_str) except ET.ParseError as e: # 抛出Pydantic可识别的验证错误 raise ValueError(f"无效的XML格式:{str(e)}") from e # 定义自定义Annotated类型 XmlElement = Annotated[ET.Element, BeforeValidator(parse_xml)] # 使用自定义类型的模型 class XmlModel(BaseModel): content: XmlElement # 测试用例 if __name__ == "__main__": # 有效XML valid_xml = "<root><item>test</item></root>" model = XmlModel(content=valid_xml) print(model.content.tag) # 输出: root # 无效XML invalid_xml = "<root><item>test</root>" try: XmlModel(content=invalid_xml) except ValidationError as e: print(e) # 输出包含XML解析错误的验证信息
方案二:自定义Pydantic类型类
如果需要在多个地方复用这个类型,推荐创建自定义类型类,直接实现Pydantic的核心schema逻辑:
import xml.etree.ElementTree as ET from pydantic import BaseModel, ValidationError from pydantic_core import core_schema from pydantic import GetCoreSchemaHandler from typing import Any class XmlElement(ET.Element): @classmethod def __get_pydantic_core_schema__( cls, source_type: Any, handler: GetCoreSchemaHandler ) -> core_schema.CoreSchema: # 定义schema规则:接受字符串输入,通过验证器转换为Element return core_schema.no_info_wrap_validator_function( cls._validate_xml, core_schema.str_schema(), ) @classmethod def _validate_xml(cls, value: str) -> ET.Element: try: return ET.fromstring(value) except ET.ParseError as e: raise ValueError(f"XML解析失败:{str(e)}") from e # 使用自定义类型的模型 class XmlModel(BaseModel): content: XmlElement # 测试用例 if __name__ == "__main__": valid_xml = "<root><item>test</item></root>" model = XmlModel(content=valid_xml) print(model.content.find("item").text) # 输出: test invalid_xml = "<root><item>test" try: XmlModel(content=invalid_xml) except ValidationError as e: print(e)
两种方案的核心都是:显式告诉Pydantic如何将输入字符串转换为ET.Element,并捕获解析错误转为Pydantic验证错误。方案一更轻量,适合单次使用;方案二更适合作为可复用的类型组件。
内容的提问来源于stack exchange,提问作者rishabhc32
相关产品推荐
相关产品推荐

