web-dev-qa-db-fra.com

recherche d'éléments par attribut avec lxml

J'ai besoin d'analyser un fichier xml pour extraire certaines données. Je n'ai besoin que de quelques éléments avec certains attributs, voici un exemple de document:

<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>

Ici, je voudrais obtenir uniquement l'article avec le type "news". Quelle est la façon la plus efficace et élégante de le faire avec lxml?

J'ai essayé avec la méthode find mais ce n'est pas très sympa:

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
43
Jérôme Pigeot

Vous pouvez utiliser xpath, par exemple root.xpath("//article[@type='news']")

Cette expression xpath renverra une liste de tous les <article/> éléments avec des attributs "type" avec la valeur "news". Vous pouvez ensuite le parcourir pour faire ce que vous voulez, ou le passer n'importe où.

Pour obtenir uniquement le contenu du texte, vous pouvez étendre le xpath comme ceci:

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()")

et cela produira ['some text', 'some text']. Ou si vous vouliez juste les éléments de contenu, ce serait "//article[@type='news']/content" -- etc.

71
Devin Jeanpierre

Juste pour référence, vous pouvez obtenir le même résultat avec 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
9
Kjir