У меня есть файл XML, который выглядит так:
xml = '''<?xml version="1.0"?>
<root>
<item>text</item>
<item2>more text</item2>
<targetroot>
<targetcontainer>
<target>text i want to get</target>
</targetcontainer>
<targetcontainer>
<target>text i want to get</target>
</targetcontainer>
</targetroot>
...more items
</root>
'''
С помощью lxml я пытаюсь получить доступ к тексту в элементе ‹ target >. Я нашел решение, но я уверен, что есть лучший и более эффективный способ сделать это. Мое решение:
target = etree.XML(xml)
for x in target.getiterator('root'):
item1 = x.findtext('item')
for target in x.iterchildren('targetroot'):
for t in target.iterchildren('targetcontainer'):
targetText = t.findtext('target')
Хотя это работает, поскольку дает мне доступ ко всем элементам в корне, а также к целевому элементу, мне трудно поверить, что это наиболее эффективное решение.
Итак, мой вопрос таков: есть ли более эффективный способ доступа к текстам ‹ target >, оставаясь в цикле root, потому что мне также нужен доступ к другим элементам.
Ответ 1 · рейтинг 3 · brandizzi
Вы можете использовать XPath:
for x in target.xpath('/root/targetroot/targetcontainer/target'):
print x.text
Мы запрашиваем все элементы, соответствующие пути. В данном случае путь /root/targetroot/targetcontainer/target, что означает
все элементы <target>, которые находятся внутри элемента <targetcontainer>, внутри элемента <targetroot>, внутри элемента <root>. Кроме того, элемент <root> должен быть корнем документа, поскольку ему предшествует /, что означает начало документа.
Кроме того, ваш XML-документ имел две проблемы. Во-первых, объявление <?xml version="1.0"?> должно быть самым первым в документе - и в этом примере ему предшествует новая строка и пробел. Кроме того, это не тег, и его не следует закрывать, поэтому </xml> в конце вашей строки следует удалить. Я уже отредактировал ваш вопрос в любом случае.
EDIT: это решение еще можно улучшить. Вам не нужно передавать все пути - вы можете просто задать все элементы <target> внутри документа. Для этого перед именем тега ставится две косые черты. Поскольку вам нужны все <target> текстов, независимо от того, где они находятся, это может быть лучшим решением. Таким образом, приведенный выше цикл можно записать так:
for x in target.xpath('//target'):
print x.text
Я попробовал это сначала, но это не сработало. Проблема, однако, заключалась в проблемах синтаксиса в XML, а не в XPath, но я попробовал другой, более длинный путь и забыл повторить этот. Извиняюсь! В любом случае, я надеюсь, что все же пролил свет на XPath :)