如何用Python依据XSD文件验证关联的两个XML文件
解决跨XML文档的ID/IDREF关联验证问题
问题分析
你当前的验证方式存在两个核心问题:
- XSD约束定义错误:
xs:unique和xs:keyref被定义在<review>元素下,而xpath="book"和xpath="review"是相对于<review>元素的路径,无法找到对应的<book>或其他<review>元素,导致约束完全失效。 - 单文档验证局限性:默认的XML Schema验证仅针对单个文档,无法检查跨文档的
xs:IDREF是否指向另一个文档中存在的xs:ID。
解决方案一:合并XML文档(推荐,符合标准Schema规范)
将两个独立的XML文件合并到一个包含根元素的文档中,同时修正XSD的约束定义,让key/keyref约束作用于整个文档的元素。
1. 修正后的XSD(file.xsd)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- 定义根元素,包含多个book和review --> <xs:element name="library"> <xs:complexType> <xs:sequence> <xs:element name="book" type="bookType" maxOccurs="unbounded"/> <xs:element name="review" type="reviewType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <!-- 定义key:确保所有book的id唯一且存在 --> <xs:key name="bookID"> <xs:selector xpath="book"/> <xs:field xpath="@id"/> </xs:key> <!-- 定义keyref:确保review的ref必须匹配某个book的id --> <xs:keyref name="reviewRef" refer="bookID"> <xs:selector xpath="review"/> <xs:field xpath="@ref"/> </xs:keyref> </xs:element> <!-- book类型定义 --> <xs:complexType name="bookType"> <xs:sequence> <xs:element name="title" type="xs:string"/> <xs:element name="author" type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> </xs:complexType> <!-- review类型定义 --> <xs:complexType name="reviewType"> <xs:sequence> <xs:element name="comment" type="xs:string"/> <xs:element name="score" type="xs:integer"/> </xs:sequence> <xs:attribute name="ref" type="xs:string" use="required"/> </xs:complexType> </xs:schema>
2. 合并后的XML文档(combined.xml)
<library> <book id="l1"> <title>El señor de los anillos</title> <author>J.R.R. Tolkien</author> </book> <review ref="l1"> <comment>Un clásico de la literatura</comment> <score>5</score> </review> </library>
3. 验证代码
from xmlschema import XMLSchema schema = XMLSchema('file.xsd') # 验证合并后的文档,此时会自动检查ref是否指向存在的book id schema.validate('combined.xml')
解决方案二:跨文档验证(保留独立文件)
如果必须保留两个独立的XML文件,可以利用xmlschema库的多文档验证能力,将两个文档加载到同一个验证上下文中,同时调整XSD约束为全局级别。
1. 修正后的XSD(file.xsd)
移除错误的xs:unique和xs:keyref,保留ID/IDREF类型:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="book" type="bookType"/> <xs:element name="review" type="reviewType"/> <xs:complexType name="bookType"> <xs:sequence> <xs:element name="title" type="xs:string"/> <xs:element name="author" type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> </xs:complexType> <xs:complexType name="reviewType"> <xs:sequence> <xs:element name="comment" type="xs:string"/> <xs:element name="score" type="xs:integer"/> </xs:sequence> <xs:attribute name="ref" type="xs:IDREF" use="required"/> </xs:complexType> </xs:schema>
2. 跨文档验证代码
使用xmlschema的XMLResource加载两个文档,共享ID池进行验证:
from xmlschema import XMLSchema, XMLResource schema = XMLSchema('file.xsd') # 加载第一个文档,获取ID池并验证 book_doc = XMLResource('file1.xml', schema=schema) book_doc.validate() # 加载第二个文档,复用第一个文档的ID池进行验证 review_doc = XMLResource('file2.xml', schema=schema, globals=book_doc.globals) review_doc.validate()
这种方式会让第二个文档的xs:IDREF检查第一个文档中的xs:ID是否存在,如果ref指向不存在的ID,会抛出验证错误。
内容的提问来源于stack exchange,提问作者Usuario86
相关产品推荐
相关产品推荐

