在Python中使用XPath和LXML

2024-09-29 09:23:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python脚本,用于解析XMLs并将某些感兴趣的元素导出到csv文件中。我现在尝试更改脚本以允许在条件下筛选XML文件,等效的XPath查询将是:

\DC\Events\Confirmation[contains(TransactionId,"GTEREVIEW")]

当我尝试使用lxml时,我的代码是:

xml_file = lxml.etree.parse(xml_file_path)
namespace = "{" + xml_file.getroot().nsmap[None] + "}"
node_list = xml_file.findall(namespace + "Events/" + namespace + "Confirmation[TransactionId='*GTEREVIEW*']")

但这似乎行不通。有人能帮忙吗? XML文件示例:

<Events>
  <Confirmation>
    <TransactionId>GTEREVIEW2012</TransactionId>
  </Confirmation>    
  <Confirmation>
    <TransactionId>GTEDEF2012</TransactionId>
  </Confirmation>    
</Events> 

所以我想要所有包含事务Id的“确认”节点,该事务Id包含字符串“GTEREVIEW”。 谢谢


Tags: 文件脚本idxmleventsnamespace事务lxml
2条回答
//Confirmation[TransactionId[contains(.,'GTEREVIEW')]]


father_tag[child_tag]  # select father_tag that has child_tag
[child_tag[filter]]    # select select child tag which match filter
[filter]

findall()不支持XPath表达式,只支持ElementPath(请参见http://effbot.org/zone/element-xpath.htm)。ElementPath不支持搜索包含特定字符串的元素。

为什么不使用XPath呢?假设文件test.xml包含示例XML,则以下操作有效:

> python
Python 2.7.9 (default, Jun 29 2016, 13:08:31) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> from lxml import etree
>>> tree=etree.parse("test.xml")
>>> tree.xpath("Confirmation[starts-with(TransactionId, 'GTEREVIEW')]")
[<Element Confirmation at 0x7f68b16c3c20>]

如果坚持使用findall(),那么最好的方法是获取具有TransactionId子节点的所有Confirmation元素的列表:

>>> tree.findall("Confirmation[TransactionId]")
[<Element Confirmation at 0x7f68b16c3c20>, <Element Confirmation at 0x7f68b16c3ea8>]

然后需要手动筛选此列表,例如:

>>> [e for e in tree.findall("Confirmation[TransactionId]")
     if e[0].text.startswith('GTEREVIEW')]
[<Element Confirmation at 0x7f68b16c3c20>]

如果您的文档包含名称空间,那么如果元素使用默认名称空间(我使用xmlns="file:xyz"作为默认名称空间),则下面将为您获取具有Confirmation子节点的所有TransactionId元素:

>>> tree.findall("//{{{0}}}Confirmation[{{{0}}}TransactionId]".format(tree.getroot().nsmap[None]))
[<Element {file:xyz}Confirmation at 0x7f534a85d1b8>, <Element {file:xyz}Confirmation at 0x7f534a85d128>]

当然还有etree.ETXPath

>>> find=etree.ETXPath("//{{{0}}}Confirmation[starts-with({{{0}}}TransactionId, 'GTEREVIEW')]".format(tree.getroot().nsmap[None]))
>>> find(tree)
[<Element {file:xyz}Confirmation at 0x7f534a85d1b8>]

这允许您组合XPath和名称空间。

相关问题 更多 >