如何在Python中验证带有多个命名空间的XML?

5 投票
1 回答
2688 浏览
提问于 2025-04-16 13:51

我正在尝试用Python 2.7写一些单元测试,以验证我对OAI-PMH架构所做的一些扩展:http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd

我遇到的问题是,多个嵌套命名空间的处理是由于上面提到的XSD中的这个规范造成的:

<complexType name="metadataType">
    <annotation>
        <documentation>Metadata must be expressed in XML that complies
        with another XML Schema (namespace=#other). Metadata must be 
        explicitly qualified in the response.</documentation>
    </annotation>
    <sequence>
        <any namespace="##other" processContents="strict"/>
    </sequence>
</complexType>

这是我正在使用的代码片段:

import lxml.etree, urllib2

query = "http://localhost:8080/OAI-PMH?verb=GetRecord&by_doc_ID=false&metadataPrefix=nsdl_dc&identifier=http://www.purplemath.com/modules/ratio.htm"
schema_file = file("../schemas/OAI/2.0/OAI-PMH.xsd", "r")
schema_doc = etree.parse(schema_file)
oaischema = etree.XMLSchema(schema_doc)

request = urllib2.Request(query, headers=xml_headers)
response = urllib2.urlopen(request)
body = response.read()
response_doc = etree.fromstring(body)

try:
    oaischema.assertValid(response_doc)
except etree.DocumentInvalid as e:
     line = 1;
     for i in body.split("\n"):
        print "{0}\t{1}".format(line, i)
        line += 1
     print(e.message)

我最终遇到了以下错误:

AssertionError: http://localhost:8080/OAI-PMH?verb=GetRecord&by_doc_ID=false&metadataPrefix=nsdl_dc&identifier=http://www.purplemath.com/modules/ratio.htm
Element '{http://www.openarchives.org/OAI/2.0/oai_dc/}oai_dc': No matching global element declaration available, but demanded by the strict wildcard., line 22

我明白这个错误的原因,因为架构要求元数据元素的子元素必须严格验证,而示例XML确实满足这个要求。

我已经在Java中写了一个有效的验证器——不过如果能在Python中实现就更好了,因为我正在构建的解决方案是基于Python的。为了让我的Java版本正常工作,我必须让我的DocumentFactory支持命名空间,否则我会遇到同样的错误。我还没有找到任何在Python中能够正确执行这种验证的有效示例。

有没有人知道我该如何让一个包含多个嵌套命名空间的XML文档(作为我的示例文档)在Python中通过验证呢?

这是我尝试验证的示例XML文档:

<?xml version="1.0" encoding="UTF-8"?> 
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/
     http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
  <responseDate>2002-02-08T08:55:46Z</responseDate>
  <request verb="GetRecord" identifier="oai:arXiv.org:cs/0112017"
       metadataPrefix="oai_dc">http://arXiv.org/oai2</request>
  <GetRecord>
   <record> 
    <header>
      <identifier>oai:arXiv.org:cs/0112017</identifier> 
      <datestamp>2001-12-14</datestamp>
      <setSpec>cs</setSpec> 
      <setSpec>math</setSpec>
    </header>
    <metadata>
      <oai_dc:dc 
     xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" 
     xmlns:dc="http://purl.org/dc/elements/1.1/" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ 
     http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
    <dc:title>Using Structural Metadata to Localize Experience of 
          Digital Content</dc:title> 
    <dc:creator>Dushay, Naomi</dc:creator>
    <dc:subject>Digital Libraries</dc:subject> 
    <dc:description>With the increasing technical sophistication of 
        both information consumers and providers, there is 
        increasing demand for more meaningful experiences of digital 
        information. We present a framework that separates digital 
        object experience, or rendering, from digital object storage 
        and manipulation, so the rendering can be tailored to 
        particular communities of users.
    </dc:description> 
    <dc:description>Comment: 23 pages including 2 appendices, 
        8 figures</dc:description> 
    <dc:date>2001-12-14</dc:date>
      </oai_dc:dc>
    </metadata>
  </record>
 </GetRecord>
</OAI-PMH>

1 个回答

0

lxml的验证文档 中找到了这个内容:

>>> schema_root = etree.XML('''\
...   <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...     <xsd:element name="a" type="xsd:integer"/>
...   </xsd:schema>
... ''')
>>> schema = etree.XMLSchema(schema_root)

>>> parser = etree.XMLParser(schema = schema)
>>> root = etree.fromstring("<a>5</a>", parser)

所以,也许你需要的是这个?(看看最后两行。):

schema_doc = etree.parse(schema_file)
oaischema = etree.XMLSchema(schema_doc)

request = urllib2.Request(query, headers=xml_headers)
response = urllib2.urlopen(request)
body = response.read()
parser = etree.XMLParser(schema = oaischema)
response_doc = etree.fromstring(body, parser)

撰写回答