сопоставление братьев и сестер в соответствии с атрибутами тегов в xml с использованием Python и libxml2 - PullRequest
4 голосов
/ 13 марта 2011


Я новичок в программировании и, возможно, где-то не хватает основ.

У меня есть xml:

<mother>
<daughter nr='1' state='nice' name='Ada'>
<daughter nr='2' state='naughty' name='Beta'>
<daughter nr='3' state='nice' name='Cecilia'>
<daughter nr='4' state='neither' name='Dora'>
<daughter nr='5' state='naughty' name='Elis'>
</mother>

мне нужно сопоставить непослушных и симпатичных дочерей по их количеству (симпатичной и ближайшей непослушной) и напечатать пары:

Ada Beta  
Cecilia Elis

мой код:

import libxml2, sys

doc = libxml2.parseFile("file.xml")
tree = doc.xpathNewContext()

nice = tree.xpathEval("//daugter[@state='nice']")

for l in nice:
   print l.prop("name")

nice_nr = []
for n in nice:
    nice_nr.append(n.prop("nr"))

# and the same for the naugty daugters

doc.freeDoc()

Так что я могу получить значения их атрибутов, но не могу понять, как составить их пары.
То, что я мог найти, это ось 'follow-sibling' для Xpath, но из всех примеров, которые я смог найти, я не уверен, можно ли ее здесь использовать. Синтаксис несколько иной, и он принимает всех следующих братьев и сестер. Любая помощь приветствуется.

Ответы [ 3 ]

3 голосов
/ 13 марта 2011
* +1000 * Используйте
 /*/daughter[@state = 'nice'][1]
| 
 /*/daughter[@state = 'nice'][1]
       /following-sibling::daughter[@state='naughty'] [1]

Выбирает пару первой хорошей дочери и ее ближайшей непослушной дочери.

Чтобы выбрать вторую такую ​​пару, используйте:

 /*/daughter[@state = 'nice'][2]
| 
 /*/daughter[@state = 'nice'][2]
       /following-sibling::daughter[@state='naughty'] [1]

... и т. Д.

Обратите внимание , что эти выражения не гарантируют, что узел будет вообще выбран - возможно, нет элементов daughter, или не каждый элемент nice daughter может иметь следующий брат daughter элемент, который непослушен.

Если гарантируется, что в документе порядок из daughter элементов строго ('nice', 'naughty), то можно использовать очень простое выражение XPath для получения всех пар:

/ * / daughter [@state = 'nice' или @state = 'naughty']

Выбирает все элементы daughter, которые являются дочерними элементами верхнего элемента и имеют чередующийся атрибут состояния со значениями: nice, naughty, nice, naughty, ...

Если используемый XPath API получает их в массив объектов , то для каждого четного k пара дочерних элементов входит в k-й и (k + 1) -й члены этого массива.

0 голосов
/ 13 марта 2011

У меня есть решение без xpath. Упорядочение дочерей по номеру также учитывается. Документ просматривается только один раз.

from lxml.etree import fromstring

data = """the-xml-above""" 

def fetch_sorted_daughters(data):
    # load data into xml document
    doc = fromstring(data)
    nice = []
    naughty = []

    # extract into doubles - number, name
    for subelement in doc:
        if subelement.tag=='daughter':
            nr = subelement.get('nr')
            name = subelement.get('name')
            if subelement.get('state')=='nice':
                nice.append((nr, name))
            if subelement.get('state')=='naughty':
                naughty.append((nr, name))
    del doc # release document

    # sort doubles
    nice.sort(key=lambda x:x[0])
    naughty.sort(key=lambda x:x[0])

    # get sorted names from doubles 
    nice = tuple([double[1] for double in nice])
    naughty = tuple([double[1] for double in naughty])

    return nice, naughty

nice, naughty = fetch_sorted_daughters(data)
pairs = zip(nice, naughty)

print pairs
0 голосов
/ 13 марта 2011

Каждое выражение XPath будет возвращать список упорядоченных узлов. Просто скрепите списки вместе, чтобы найти соответствующие пары:

xpath = lambda state: tree.xpathEval("//daughter[@state='%s']" % state)
for nodes in zip(xpath('nice'), xpath('naughty')):
    print ' '.join(n.prop('name') for n in nodes)

Выше xpath - это функция, которая оценивает выражение XPath, которое возвращает дочерних элементов, соответствующих данному state. Затем два списка передаются в zip, который будет возвращать кортеж i-х элементов из каждого списка.

Если дочерние узлы перечислены в файле XML не по порядку, вы можете отсортировать узлы по атрибуту nr, прежде чем передавать их в zip.

...