Как получить элементы в диапазоне в lxml - PullRequest
0 голосов
/ 04 июня 2019

У меня есть xml, похожий на следующий xml.Я пытаюсь получить элементы с именем "elem" на основе атрибута "id" некоторого диапазона.

Например: получить все элементы "elem" от id = 4 до id = 8.

<all_levels>
<level1>
    <level2>
        <level3>
        <elem id="1"> </elem>
        <elem id="2"> </elem>
        </level3>
        <level3>
        <elem id="3"> </elem>
        <elem id="4"> </elem>
        </level3>
    </level2>
    <level2>
        <level3>
        <elem id="5"> </elem>
        <elem id="6"> </elem>
        </level3>
        <level3>
        <elem id="7"> </elem>
        <elem id="8"> </elem>
        </level3>
    </level2>
</level1>
<level1>
    <level2>
        <level3>
        <elem id="9"> </elem>
        <elem id="10"> </elem>
        </level3>
        <level3>
        <elem id="11"> </elem>
        <elem id="12"> </elem>
        </level3>
    </level2>
    <level2>
        <level3>
        <elem id="13"> </elem>
        <elem id="14"> </elem>
        </level3>
        <level3>
        <elem id="15"> </elem>
        <elem id="16"> </elem>
        </level3>
    </level2>
</level1>
</all_levels>

Я пробовал два метода: 1) Использование xpath для получения необходимых элементов "elem", таких как получение элементов из диапазона (4,8)

from lxml import etree
sample_xml = etree.parse("sample_xml.xml")
elem1 = sample_xml.xpath("//word[@id = '%s']" % str(4))[0]
elem2 = sample_xml.xpath("//word[@id = '%s']" % str(5))[0]
elem3 = sample_xml.xpath("//word[@id = '%s']" % str(6))[0]
elem4 = sample_xml.xpath("//word[@id = '%s']" % str(7))[0]
elem5 = sample_xml.xpath("//word[@id = '%s']" % str(8))[0]

, но если диапазон большой, это отнимает слишком много временичтобы получить все элементы.

2) используйте xpath, чтобы получить первый элемент в диапазоне, используйте метод getnext (), чтобы получить sibilings

from lxml import etree
sample_xml = etree.parse("sample_xml.xml")
elem1 = sample_xml.xpath("//word[@id = '%s']" % str(4))[0]
elems = [elem1]
curr_word = elem1
current_id = 4
while(current_id <= 8):
    curr_elem = curr_word.getnext()
    elems.append(curr_elem)
    current_id += 1

, но проблема в том, что getnext () получает толькоЭлем в том же дереве.поэтому он не может получить все остальные элементы.

Есть ли лучший способ получить элементы в диапазоне лучше, чем использование xpath?

1 Ответ

1 голос
/ 04 июня 2019

Кажется, что мы можем получить все "elem", чьи атрибуты "id" попадают в определенный диапазон, эффективно используя xpath.

Ниже приведены два метода. Я использовал магию ячейки "%% time", чтобы измерить, сколько времени занял каждый подход.

from lxml import etree
sample_xml = etree.parse("sample_xml.xml")

Метод 1:

%%time
start_heading_id = 4
ending_heading_id = 1000
elem1 = sample_xml.xpath("//elem[@id = '%s']" % str(start_heading_id))[0]
elems = [elem1]
curr_word = elem1
current_id = start_heading_id
while(current_id <= ending_heading_id):
    curr_elem = sample_xml.xpath("//elem[@id = '%s']" % str(current_id+1))[0]
    elems.append(curr_elem)
    current_id += 1

Вывод (для получения всех элементов потребовалось 13,2 секунды):

CPU times: user 13.2 s, sys: 23.6 ms, total: 13.2 s
Wall time: 13.2 s

Метод 2:

%%time
start_heading_id = 4
ending_heading_id = 1000
elems = sample_xml.xpath("//elem[@id >= '%d' and @id <= '%d']" % (start_heading_id,ending_heading_id))

Вывод (для получения всех элементов потребовалось 0,00387 секунд):

CPU times: user 39.2 ms, sys: 1.25 ms, total: 40.5 ms
Wall time: 38.7 ms
...