lxml解析含空xmlns属性的XSD报错,无需修改XSD的解决方法是什么?
报错原因
lxml的XML Schema解析器严格遵循W3C的XML Schema规范,出现该报错的根本原因是你的XSD文件存在不符合严格规范的配置:
- XSD根节点
<xs:schema>声明了xmlns="",将当前文档的默认命名空间设置为空,但是没有显式声明targetNamespace=""属性指定Schema的目标命名空间。 - 当你在
<xs:element ref="inner"/>中引用元素时,受默认命名空间xmlns=""的影响,lxml会认为你要引用空命名空间下的inner元素,但因为Schema没有显式声明目标命名空间为空,也没有显式导入空命名空间,就会触发跨命名空间引用的报错。 - C#的校验器和Python的xmlschema库做了兼容性处理,会隐式将该类XSD的目标命名空间识别为空,因此不会报错,只有lxml的严格校验会触发该问题。
无需修改原始XSD的解决方案
你可以在内存中动态处理读取到的XSD内容,完全不需要修改原始的第三方XSD文件,也不会增加后续的维护成本,推荐两种稳妥的处理方式:
方法1:DOM节点修改(最稳妥,不会误伤内容)
先将XSD内容解析为DOM节点,删除根节点的空xmlns属性后再生成校验Schema,示例代码如下:
from io import StringIO from lxml import etree # 读取原始XSD内容 with open("你的第三方XSD文件路径", "r", encoding="utf-8") as f: raw_xsd = f.read() # 内存中解析XSD并修改属性 xsd_dom = etree.parse(StringIO(raw_xsd)) schema_root = xsd_dom.getroot() # 仅删除根节点的空xmlns属性,不修改其他内容 if schema_root.attrib.get("xmlns") == "": del schema_root.attrib["xmlns"] # 用修改后的DOM生成Schema对象 schema = etree.XMLSchema(schema_root) # 后续校验逻辑和原来完全一致 xml_content = "<outer> <inner><a>1</a><b>2</b></inner> <c>3</c> </outer>" print(schema.validate(etree.parse(StringIO(xml_content))))
方法2:字符串正则替换(实现最简单)
如果你的XSD内容结构固定,也可以直接用正则替换掉根节点的xmlns=""属性:
import re from io import StringIO from lxml import etree with open("你的第三方XSD文件路径", "r", encoding="utf-8") as f: raw_xsd = f.read() # 替换根节点的空xmlns属性 processed_xsd = re.sub(r'<xs:schema([^>]*?)\s+xmlns=""([^>]*)>', r'<xs:schema\1\2>', raw_xsd) schema = etree.XMLSchema(file=StringIO(processed_xsd)) # 后续校验逻辑不变
两种方法都不需要修改原始XSD文件,即使后续第三方XSD更新,处理逻辑也可以正常生效。
内容的提问来源于stack exchange,提问作者Arthur Tacca
相关产品推荐
相关产品推荐

