125 lines
4.3 KiB
Markdown
125 lines
4.3 KiB
Markdown
---
|
||
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 # 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, où l'on référence des éléments par rapport à leur "chemin" dans le document
|
||
|
||
La plus simple des méthodes disponibles consiste à se baser sur le XPATH pour trouver des éléments :
|
||
|
||
```{.python .numberLines}
|
||
from lxml import etree
|
||
|
||
tree = 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 = tree.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
|
||
|
||
tree = 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 = tree.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/)
|