lxml仅识别同一命名空间多导入XSD中的首个文件,求排查原因
问题描述
我使用lxml依据XSD Schema验证XML文件时遇到一个问题:当将btype.xsd导入同一命名空间时,lxml无法识别第二个导入的BType类型;但为btype.xsd设置单独命名空间时,验证可正常工作。
这套XSD在Apache Camel中即使同一命名空间多次导入也能正常工作,请问是lxml存在问题还是我的XSD编写有误?
相关XSD文件
main.xsd
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:bo="http://loremipsum.org/1/" targetNamespace="http://loremipsum.org/bi/1/" attributeFormDefault="unqualified" version="1.0"> <xs:import namespace="http://loremipsum.org/1/" schemaLocation="../atype.xsd"/> <xs:import namespace="http://loremipsum.org/1/" schemaLocation="../btype.xsd"/> <xs:element name="batch"> <xs:complexType> <xs:sequence> <xs:element name="atype" type="bo:AType"> </xs:element> <xs:element name="btype" type="bo:BType"> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
atype.xsd
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://loremipsum.org/1/" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0"> <xs:complexType name="AType"> <xs:sequence> <xs:element name="ecm" type="xs:boolean" minOccurs="0"> </xs:element> <xs:element name="type" type="xs:boolean" minOccurs="0"> </xs:element> </xs:sequence> </xs:complexType> </xs:schema>
btype.xsd
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://loremipsum.org/1/" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0"> <xs:complexType name="BType"> <xs:sequence> <xs:element name="name" type="xs:string" minOccurs="0"> </xs:element> <xs:element name="email" type="xs:string" minOccurs="0"> </xs:element> </xs:sequence> </xs:complexType> </xs:schema>
解答
你的XSD写法不符合W3C XML Schema规范。根据规范,同一个命名空间只能被导入一次——后续针对同一命名空间的<xs:import>会被处理器忽略。
Apache Camel能正常工作,是因为它使用的XSD处理器(如Apache Xerces)可能做了非标准扩展,允许合并同一命名空间的多个导入文件。但lxml依赖的libxml2遵循严格的规范,只会处理第一个针对该命名空间的导入,后续的btype.xsd不会被加载,自然无法识别BType类型。
正确解决方案
有两种规范内的解决方式:
- 合并文件:将
AType和BType定义合并到同一个XSD文件中,在main.xsd里只导入一次该命名空间。 - 使用
<xs:include>:因为atype.xsd和btype.xsd属于同一命名空间,在atype.xsd中用<xs:include>引入btype.xsd,然后main.xsd只保留对该命名空间的一次导入。
示例修改后的atype.xsd:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://loremipsum.org/1/" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0"> <xs:include schemaLocation="../btype.xsd"/> <xs:complexType name="AType"> <xs:sequence> <xs:element name="ecm" type="xs:boolean" minOccurs="0"> </xs:element> <xs:element name="type" type="xs:boolean" minOccurs="0"> </xs:element> </xs:sequence> </xs:complexType> </xs:schema>
同时将main.xsd中重复的<xs:import>删除,只保留一行:
<xs:import namespace="http://loremipsum.org/1/" schemaLocation="../atype.xsd"/>
内容的提问来源于stack exchange,提问作者Arunselvan
相关产品推荐
相关产品推荐

