2012-11-19 85 views
3

我有一個XML來解析這對我來說非常棘手。Python,lxml - 獲取兄弟標籤的(大)孩子的文本

<bundles> 
    <bundle> 
    <bitstreams> 
     <bitstream> 
     <id>1234</id> 
     </bitstream> 
    </bitstream> 
    <name>FOO</name> 
    </bundle> 
    <bundle> ... </bundle> 
</bundles> 

我想通過這個XML迭代並找到所有ID比特流內值的其中元素的值是「富」。我對任何未命名爲「FOO」的軟件包都不感興趣,並且軟件包中可能包含任意數量的軟件包和任意數量的比特流。

我一直在使用tree.findall('./bundle/name')找到FOO束但這只是返回一個列表,我不能爲ID值步:

for node in tree.findall('./bundle/name'): 
if node.text == 'FOO': 
id_values = tree.findall('./bundle/bitstreams/bitstream/id') 
for value in id_values: 
    print value.text 

此打印出所有 id值,而不是捆綁'FOO'的那些。

我怎樣才能通過此樹遍歷,找到 FOO,藉此節點和收集ID嵌套在它值?這裏的XPath參數是不正確的嗎?

我正在Python中工作,與lxml綁定 - 但我相信任何XML解析器都會好的;這些不是大型的XML樹。

+2

你能告訴我們你到目前爲止的代碼? –

回答

6

您可以使用xpath來達到目的。以下Python代碼工作完美:

import libxml2 
data = """ 
<bundles> 
    <bundle> 
    <bitstreams> 
     <bitstream> 
     <id>1234</id> 
     </bitstream> 
    </bitstreams> 
    <name>FOO</name> 
    </bundle> 
</bundles> 
""" 
doc = xmllib2.parseDoc(data) 
for node in doc.xpathEval('/bundles/bundle/name[.="FOO"]/../bitstreams/bitstream/id'): 
    print node 

或使用lxmldata是一樣的,在上面的例子):

from lxml import etree 

bundles = etree.fromstring(data) 

for node in bundles.xpath('bundle/name[.="FOO"]/../bitstreams/bitstream/id'): 
    print(node.text) 

輸出:

1234 

如果<bitstreams>元件總是先<name>元素,您還可以使用更高效的xpath表達式:

'bundle/name[.="FOO"]/preceding-sibling::bitstreams/bitstream/id' 
+0

基本上你會找到名稱爲foo的包,然後轉到父節點並返回到比特流ID ... – Nautical

+2

也添加了一個'lxml'示例,因爲它是OP所使用的。希望沒關係。 –

+0

是的,這個工作正常。我完全誤解了lxml中的XPath。 – wxs

2

你的問題之一是「這裏的XPath參數不正確嗎?」。那麼,findall()不接受XPath表達式。它使用了一個叫做ElementPath的簡化版本。此外,您第二次致電findall()與第一次電話的結果無關,所以它只會返回id s中的所有bundle s。

少許修改你的代碼也應努力(這是基本相同的XPath表達式):

for node in tree.findall('./bundle/name'): 
    if node.text != 'FOO': 
     continue 
    id_values = node.getparent().findall('./bitstreams/bitstream/id') 
    for value in id_values: 
     print value.text 
相關問題