2016-11-15 74 views
1

我有一個python腳本,用於解析XML並將其導出到csv文件的某些感興趣的元素中。我曾試圖改變現在的腳本允許標準下的XML文件的過濾,相當於XPath查詢將是:在Python中與LXML一起使用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,其中包括字符串「GTEREVIEW」全部「確認」的節點。 感謝

+0

其中是您的xml文件? – SomeDude

+0

我已更新問題。 – naiminp

回答

2

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>] 

如果您的文檔CON含有雜質的命名空間,下面將讓你有TransactionId子節點的所有Confirmation元素,前提是該元素使用默認的命名空間(我用xmlns="file:xyz"作爲默認的命名空間):

>>> 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和名稱空間。

+0

非常感謝您的回答!不幸的是,我的文檔中有一個名稱空間,導致Xpath返回一個空列表。從文件中刪除名稱空間後,代碼似乎工作。有沒有解決的辦法?該文件基本上以 並以 naiminp

+0

結尾。你仍然可以用'findall()'來使用第二種方法。您只需在返回的節點列表上執行過濾。 – Markus

0
//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] 
+0

只是添加一些解釋 –