---
title: Manipuler des fichiers texte XML
author: Steve Kossouho
---

# Découvrir comment décoder des arborescences XML

----

## Structure d'un fichier XML

Le format XML (_Extensible Markup Language_) est un format de texte permettant de représenter des données
hiérarchiques (avec un élément principal) arbitraires. Le contenu d'un document de ce type utilise une syntaxe
à base de balises telles qu'on les retrouve en SGML ou HTML :

```xml
<CATALOG>
    <CD>
        <TITLE>Empire Burlesque</TITLE>
        <ARTIST>Bob Dylan</ARTIST>
        <COUNTRY>USA</COUNTRY>
        <COMPANY>Columbia</COMPANY>
        <PRICE>10.90</PRICE>
        <YEAR>1985</YEAR>
    </CD>
</CATALOG>
```

Extrait de document d'exemple. [Lien du document](https://www.w3schools.com/xml/cd_catalog.xml)

----

## Définition de la structure d'un document XML

Professionnellement, il peut être intéressant pour un producteur, ou un consommateur de fichiers
XML d'avoir accès à un document normalisant le contenu possible d'un fichier XML.

Pendant un temps, seules les [DTD](https://fr.wikipedia.org/wiki/Document_type_definition) existaient
mais étaient écrites dans un format assez indigeste. En 2001, le [XML Schema](https://fr.wikipedia.org/wiki/XML_Schema)
est plus accessible, et certains outils Python sont capables d'utiliser ces documents pour valider une
structure XML.

----

## Utilisation du XML en Python

Si l'on connaît la structure d'un document XML, il est possible de le lire facilement en Python.
Même si les packages de la bibliothèque standard fonctionnent, ils sont **spécifiquement**
indiqués comme sensibles à des attaques de document malicieusement formé (typiquement XML Bomb, attaque sur le
système de références en XML).

Parmi les autres bibliothèques, la plus utilisée dans l'écosystème Python semble être [LXML](https://lxml.de)

```bash {.numberLines}
pip install lxml types-lxml # pour installer la bibliothèque externe
```

----

### Exemple de démo de LXML

Pour naviguer dans un document XML, il existe plusieurs façons de faire :

- Méthode récursive, où l'on récupère un élément pour parcourir ses enfants
- Méthode [XPath]{.naming}, où l'on référence des éléments par rapport à leur "chemin" dans le document
- Méthode [ElementPath]{.naming}, proposée par LXML via les méthodes `find` et `findall`

La plus simple des méthodes disponibles consiste à se baser sur le XPATH pour trouver des éléments :

```python {.numberLines}
from lxml import etree

root = etree.parse(r"source.xml")  # récupère l'élément racine
# Récupérer les éléments de la racine CATALOG qui ont le nom CD
items = root.xpath("/CATALOG/CD")
```

- [Guide complet sur le XPath](https://www.ionos.com/digitalguide/websites/web-development/xpath-tutorial/)
- [Exemple plus simple sur le XPath](https://www.w3schools.com/xml/xpath_syntax.asp)


----

### Parcourir des résultats XPATH

Dans l'exemple précédent, nous avons pu récupérer, via une "requête" XPATH, un possible ensemble d'éléments.
Ces éléments peuvent être parcourus avec une simple boucle `for`{.python} :

```python {.numberLines}
from lxml import etree

root = etree.parse(r"source.xml")  # récupère l'élément racine
# Récupérer les éléments de la racine CATALOG qui ont le nom CD
items = root.xpath("/CATALOG/CD")

for cd in items:
    for attribute in cd:
        # afficher le nom et les attributs, puis le texte
        print(attribute.tag, attribute.attrib, attribute.text)
```

----

## Propriétés des éléments `_ElementTree`

Les éléments du modèle de document sont représentés sous la forme d'instances de la classe 
`_ElementTree`. Pour en extraire des données, de nombreuses méthodes sont documentées officiellement,
mais les attributs les plus simples à retenir sont les suivants :

- `attrib` (`dict`{.python}) : renvoie les attributs de la balise;
- `tag` (`str`{.python}) : renvoie le nom de la balise;
- `text` (`str`{.python}) : renvoie le texte direct de la balise.

Également, un élément peut être parcouru avec une boucle `for`{.python} et renverra à
chaque itération chacun de ses éléments enfants, même si la méthode suivante existe aussi :

- `getchildren()`{.python} : renvoie un itérable des éléments enfants.

----

## Documentation officielle de LXML

- [Documentation officielle (en anglais)](https://lxml.de)
- [Tutorial LXML par Oxylabs](https://oxylabs.io/blog/lxml-tutorial)
- [Sérialiser des objets Python en XML](https://pypi.org/project/lxml-dataclass/)
