2012-11-19 5 views
3

구문 분석 할 XML이 있는데, 이는 나에게 매우 까다로운 증명입니다.Python, lxml - 형제 태그 (그랜드) 자식 텍스트를 가져옵니다.

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

나는이 XML을 반복하고 이름 요소의 값이 'FOO'인 번들비트 스트림의 내부의 모든 ID 값을 찾을 싶습니다. 나는 'FOO'라는 이름의 번들에는 관심이 없으며, 묶음에는 몇 개의 번들과 비트 스트림이있을 수 있습니다.

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 

모든 아이디 값을 출력 : 나는 FOO 번들을 찾을 tree.findall('./bundle/name')를 사용하고 있지만, 이것은 단지 내가 ID 값을 통해 단계 수없는 목록을 반환

번들 'FOO'의 것들은 아닙니다.

내가이 나무를 통해 반복 할 수있는 방법은 이름 FOO와 번들을 찾아 값이 그 안에 중첩 된 ID를이 번들 노드를 가지고 수집? 여기서 XPath 인수가 올바르지 않습니까?

저는 파이썬에서 lxml 바인딩으로 작업하고 있습니다. 그러나 모든 XML 파서는 괜찮을 것이라고 생각합니다. 이것들은 큰 XML 트리가 아닙니다.

+2

당신이 우리에게 지금까지 가지고있는 코드를 게재 할 수 있습니까? –

답변

6

xpath을 사용하면 이러한 목적을 달성 할 수 있습니다. 다음 파이썬 코드는 완벽하게 작동합니다

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 

또는 lxml를 사용하여 (data 위의 예에서와 같이 동일) :

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

기본적으로 U는 foo라는 이름의 번들을 찾았습니다 .. 부모 노드로 가서 비트 스트림 ID로 되돌아갑니다 ... – Nautical

+2

OP가 사용했던 것이기 때문에'lxml' 예제도 추가되었습니다. 희망 이니. –

+0

예, 올바르게 작동했습니다. 나는 lxml에서 XPath를 완전히 오해하고 있었다. – wxs

2

"XPath 인수가 올바르지 않습니까?" 음, findall()은 XPath 표현식을 허용하지 않습니다. 그것은 ElementPath이라는 간단한 버전을 사용합니다. 또한 findall()에 대한 두 번째 호출은 어떤 식 으로든 첫 번째 호출 결과와 관련이 없으므로 bundle 초 중 id 초를 반환합니다.

코드에 약간의 수정은 (는 기본적으로 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