使用Element Tree findall解析XML命名空间

时间:2015-05-04 21:04:24

标签: python xml docusignapi

如何在给定以下xml的情况下使用查询元素树findall('Email')

<DocuSignEnvelopeInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.docusign.net/API/3.0">
    <EnvelopeStatus>
        <RecipientStatus>
                <Type>Signer</Type>
                <Email>joe@gmail.com</Email>
                <UserName>Joe Shmoe</UserName>
                <RoutingOrder>1</RoutingOrder>
                <Sent>2015-05-04T09:58:01.947</Sent>
                <Delivered>2015-05-04T09:58:14.403</Delivered>
                <Signed>2015-05-04T09:58:29.473</Signed>
        </RecipientStatus>
    </EnvelopeStatus>
</DocuSignEnvelopeInformation>

我觉得它与命名空间有关,但我不确定。我看着docs,没有运气。

tree = <xml.etree.ElementTree.ElementTree object at 0x7f27a47c4fd0>
root = tree.getroot()
root
<Element '{http://www.docusign.net/API/3.0}DocuSignEnvelopeInformation' at 0x7f27a47b8a48>

root.findall('Email')
[]

1 个答案:

答案 0 :(得分:3)

您应该更仔细地阅读文档,特别是Parsing XML with Namespaces部分,其中包含一个几乎完全符合您要求的示例。

但即使没有文档,答案实际上也包含在您的示例输出中。当您打印文档的根元素时......

>>> tree = etree.parse(open('data.xml'))
>>> root = tree.getroot()
>>> root
<Element {http://www.docusign.net/API/3.0}DocuSignEnvelopeInformation at 0x7f972cd079e0>

...您可以看到它使用名称空间前缀(DocuSignEnvelopeInformation)打印了根元素名称({http://www.docusign.net/API/3.0})。您可以将此相同的前缀用作findall的参数的一部分:

>>> root.findall('{http://www.docusign.net/API/3.0}Email')

但这本身并不起作用,因为这只会找到Email元素,它们是根元素的直接子元素。您需要提供ElementPath表达式,以使findall执行整个文档的搜索。这有效:

>>> root.findall('.//{http://www.docusign.net/API/3.0}Email')
[<Element {http://www.docusign.net/API/3.0}Email at 0x7f972949a6c8>]

您还可以使用XPath和名称空间前缀执行类似的搜索,如下所示:

>>> root.xpath('//docusign:Email',
... namespaces={'docusign': 'http://www.docusign.net/API/3.0'})
[<Element {http://www.docusign.net/API/3.0}Email at 0x7f972949a6c8>]

这使您可以使用类似XML的namespace:前缀而不是LXML命名空间语法。