Поиск элементов по атрибуту с помощью lxml
Мне нужно проанализировать XML файл, чтобы извлечь некоторые данные.
Мне нужны только некоторые элементы с определенными атрибутами, вот пример документа:
<root>
<articles>
<article type="news">
<content>some text</content>
</article>
<article type="info">
<content>some text</content>
</article>
<article type="news">
<content>some text</content>
</article>
</articles>
</root>
Здесь я хотел бы получить только статью с типом "новости".
Какой самый эффективный и элегантный способ сделать это с помощью lxml?
Я попытался с помощью метода find, но это не очень приятно:
from lxml import etree
f = etree.parse("myfile")
root = f.getroot()
articles = root.getchildren()[0]
article_list = articles.findall('article')
for article in article_list:
if "type" in article.keys():
if article.attrib['type'] == 'news':
content = article.find('content')
content = content.text
Ответы
Ответ 1
Вы можете использовать xpath, например. root.xpath("//article[@type='news']")
Это выражение xpath вернет список всех <article/>
элементов с атрибутами типа с значением "новости". Затем вы можете перебирать его, чтобы делать то, что хотите, или передавать его где угодно.
Чтобы получить только текстовое содержимое, вы можете расширить xpath так:
root = etree.fromstring("""
<root>
<articles>
<article type="news">
<content>some text</content>
</article>
<article type="info">
<content>some text</content>
</article>
<article type="news">
<content>some text</content>
</article>
</articles>
</root>
""")
print root.xpath("//article[@type='news']/content/text()")
и это выведет ['some text', 'some text']
. Или, если вам просто нужны элементы контента, это будет "//article[@type='news']/content"
- и т.д.
Ответ 2
Для справки вы можете добиться того же результата с помощью findall
:
root = etree.fromstring("""
<root>
<articles>
<article type="news">
<content>some text</content>
</article>
<article type="info">
<content>some text</content>
</article>
<article type="news">
<content>some text</content>
</article>
</articles>
</root>
""")
articles = root.find("articles")
article_list = articles.findall("article[@type='news']/content")
for a in article_list:
print a.text