Переход с амары на lxml в Python - PullRequest
1 голос
/ 23 ноября 2010

Я пытаюсь выполнить с библиотекой lxml что-то вроде этого: http://www.xml.com/pub/a/2005/01/19/amara.html

from amara import binderytools

container = binderytools.bind_file('labels.xml')
for l in container.labels.label:
    print l.name, 'of', l.address.city

но мне было труднее всего почувствовать себя мокрым! Я хочу сделать следующее: спуститься к корневому узлу с именем «X», затем спуститься к его второму дочернему элементу с именем «Y», затем захватить все его дочерние элементы с именем «Z», затем из них останутся только дочерние элементы, имеющие атрибут 'name' установлен в 'bacon', затем для каждого оставшегося узла посмотрите на все его дочерние элементы с именем 'W' и оставьте только подмножество на основе некоторого фильтра, который просматривает только дочерние элементы W с именами A, B и C. Затем Мне нужно обработать их следующим (неоптимизированным) псевдокодом:

result = []
X = root(doc(parse(xml_file_name)))
Y = X[1] # Second child
Zs = Y.children()
for Z in Zs:
    if Z.name != 'bacon': continue # skip
    Ws = Z.children()
    record = []
    assert(len(Ws) == 9)
    W0 = Ws[0]
    assert(W0.A == '42')
    record.append(str(W0.A) + " " + W0.B + " " + W0.C))
    ...
    W1 = Ws[1]
    assert(W1.A == '256')
    ...
    result.append(record)

Это своего рода то, чего я пытаюсь достичь. Прежде чем я попытаюсь сделать этот код чище, я бы хотел, чтобы он работал.

Пожалуйста, помогите, так как я заблудился в этом API. Дайте мне знать, если у вас есть вопросы.

1 Ответ

3 голосов
/ 23 ноября 2010
import lxml.etree as le
import io

content='''\
<foo><X><Y>skip this</Y><Y><Z name="apple"><W>not here</W></Z>
<Z name="bacon"><W><A>42</A><B>b</B><C>c</C></W><W><A>256</A><B>b</B><C>c</C></W></Z>
<Z name="bacon"><W><A>42</A><B>b</B><C>c</C></W><W><A>256</A><B>b</B><C>c</C></W></Z>
</Y></X></foo>
'''
doc=le.parse(io.BytesIO(content))
# print(le.tostring(doc, pretty_print=True))
result=[]
Zs=doc.xpath('//X/Y[2]/Z[@name="bacon"]')
for Z in Zs:
    Ws=Z.xpath('W')
    record=[]
    assert(len(Ws)==2)  #<--- Change to 9        
    abc=Ws[0].xpath('descendant::text()')
    # print(abc)
    # ['42', 'b', 'c']
    assert(abc[0] == '42')
    record.append(' '.join(abc))
    abc=Ws[1].xpath('descendant::text()')    
    assert(abc[0] == '256')
    result.append(record)
print(result)
# [['42 b c'], ['42 b c']]

Это может быть способ затянуть внутренний цикл, хотя я только догадываюсь, какие записи вы хотите сохранить:

for Z in Zs:
    Ws=Z.xpath('W')
    assert(len(Ws)==2)  #<--- Change to 9
    a_vals=('42','256')
    for W,a_val in zip(Ws,a_vals):
        abc=W.xpath('descendant::text()')
        assert(abc[0] == a_val)
        result.append([' '.join(abc)])
print(result)
# [['42 b c'], ['256 b c'], ['42 b c'], ['256 b c']]
...