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

Parse XML namespace with Element Tree findall

如何使用查询元素树 findall('Email') 给定以下 xml?

<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')
[]

您应该更仔细地阅读文档,尤其是关于 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>

...您可以看到它打印了带有命名空间前缀 ({http://www.docusign.net/API/3.0}) 的根元素名称 (DocuSignEnvelopeInformation)。您可以使用相同的前缀作为 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-like namespace: 前缀而不是 LXML 命名空间语法。