XML et python

XML c'est quoi?

XML pour Extensible Markup Language (langage de balisage extensible en français) est un langage informatique qui permet l'échange de données entre deux environnements hétérogènes. Un document XML est un arbre composé de noeuds qui peuvent être des éléments ou des attributs.

Un document XML

Voici un exemple de document XML, que nous avons enregistré sous le nom de data.xml

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user data-id="101">
        <nom>Zorro</nom>
        <metier>Danseur</metier>
    </user>
    <user data-id="102">
        <nom>Hulk</nom>
        <metier>Footballeur</metier>
    </user>
    <user data-id="103">
        <nom>Zidane</nom>
        <metier>Star</metier>
    </user>
    <user data-id="104">
        <nom>Beans</nom>
        <metier>Epicier</metier>
    </user>
    <user data-id="105">
        <nom>Batman</nom>
        <metier>Veterinaire</metier>
    </user>
    <user data-id="106">
        <nom>Spiderman</nom>
        <metier>Veterinaire</metier>
    </user>
</users>

La première ligne indique l'encodage, on reste toujours dans l'encodage UTF-8. Ensuite on remarque que la balise "users" possède d'autres balises "user" qui elles même possèdent leurs propres balises. Les données sont hiérarchisées dans un arbre et chaque noeud apporte une information.

Lire un XML

Voici un petit script qui affiche tous les noms des user.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from lxml import etree

tree = etree.parse("data.xml")
for user in tree.xpath("/users/user/nom"):
    print(user.text)

La liste suivante devrait s'afficher:

Zorro
Hulk
Zidane
Beans
Batman
Spiderman

Vous pouvez afficher les attributs des balises:

tree = etree.parse("data.xml")
for user in tree.xpath("/users/user"):
    print(user.get("data-id"))

Résultat:

101
102
103
104
105
106

Vous pouvez affiner l'affichage en proposant de n'afficher que les user dont le métier est Veterinaire.

tree = etree.parse("data.xml")
for user in tree.xpath("/users/user[metier='Veterinaire']/nom"):
    print(user.text)

Ce qui devrait afficher:

Batman
Spiderman

Créer un xml

Vous pouvez créer un XML:

users = etree.Element("users")
user = etree.SubElement(users, "user")
user.set("data-id", "101")
nom = etree.SubElement(user, "nom")
nom.text = "Zorro"
metier = etree.SubElement(user, "metier")
metier.text = "Danseur"
print(etree.tostring(users, pretty_print=True))

Résultat

<users>
    <user data-id="101">    
        <nom>Olivier</nom>
        <metier>Danseur</metier> 
    </user>
</users>

Code pour arriver au document XML initial:

users = etree.Element("users")

users_data = [
("101", "Zorro", "Danseur"),
("102", "Hulk", "Footballeur"),
("103", "Zidane", "Star"),
("104", "Beans", "Epicier"),
("105", "Batman", "Veterinaire"),
("106", "Spiderman", "Veterinaire"),
]

for user_data in users_data:
    user = etree.SubElement(users, "user")
    user.set("data-id", user_data[0])
    nom = etree.SubElement(user, "nom")
    nom.text = user_data[1]
    metier = etree.SubElement(user, "metier")
    metier.text = user_data[2]


print(etree.tostring(users, pretty_print=True))

Les méthodes des noeuds

Si vous voulez approfondir vos connaissances sur la lib lxml, il existe plein d'autres méthodes associées aux noeuds que vous pouvez voir en lançant la commande help(<noeuds>). L'aide est en anglais et comme je suis sympa, je vous l'ai traduite:

addnext(element)      : Ajoute un élément en tant que frère juste après l'élément
addprevious(element)  : Ajoute un élément en tant que frère juste avant l'élément
append(element)       : Ajoute un sous-élément à la fin de l'élément 
clear()               : Supprime tous les sous-éléments
extends(elements)     : Etend les éléments passé en paramètre
find(path)            : Recherche le premier sous-élément qui correspond au tag/path
findall(path)         : Recherche tous les sous-éléments qui correspondent au tag/path
findtext(path)        : Trouve le texte du premier sous-élément qui correspond au tag/path
get(key)              : Recupère l'attribut d'un élément
getchildren()         : Retourne tous les enfants d'un élément ! attention déprécié pour list(element)
getnext()             : Retourne le prochain élément frère
getparent()           : Retourne le parent de l'élément
getprevious()         : Retourne l'élément frère précédant
index(child)          : Trouve la position de l'élément
insert(index)         : Insère un sous-élément à la position indiquée
items()               : Retourne les attributs d'un élément (dans un ordre aléatoire)
keys()                : Retourne une liste des noms des attributs
remove(element)       : Supprime l'élément passé en paramètre
replace(el1, el2)     : Remplace el1 par el2
set(key, value)       : Créer un attribut avec une valeur
values()              : Retourne les valeurs des attributs
xpath(path)           : Evalue une expression xpath

Pour des informations complémentaires je vous conseille ce site: lxml.fr .