Python: Trier les balises d'un fichier XML avec BeautifulSoup

BeautifulSoup est un module Python qui permet de manipuler très facilement n'importe quel fichier XML.

Pour l'installer, rien de plus simple que:

$ python3 -m pip install --upgrade bs4

Exemple avec le fichier XML suivant

<?xml version="1.0" encoding="utf-8"?>
<towns>
 <town name="Paris"/>
 <town name="Lyon"/>
 <town name="Marseille"/>
 <town name="Nantes"/>
 <town name="Ancenis"/>
 <town name="Bordeaux"/>
 <town name="Toulouse"/>
 <town name="Rouen"/>
 <town name="Brest"/>
</towns>

On importe le XML à l'aide du module BeautifulSoup

>>> from bs4 import BeautifulSoup as bs
>>> xml = bs("""<?xml version="1.0" encoding="utf-8"?>
<towns>
 <town name="Paris"/>
 <town name="Lyon"/>
 <town name="Marseille"/>
 <town name="Nantes"/>
 <town name="Ancenis"/>
 <town name="Bordeaux"/>
 <town name="Toulouse"/>
 <town name="Rouen"/>
 <town name="Brest"/>
</towns>""", 'xml')
>>> xml
<?xml version="1.0" encoding="utf-8"?>
<towns>
<town name="Paris"/>
<town name="Lyon"/>
<town name="Marseille"/>
<town name="Nantes"/>
<town name="Ancenis"/>
<town name="Bordeaux"/>
<town name="Toulouse"/>
<town name="Rouen"/>
<town name="Brest"/>
</towns>
>>>

Je souhaite trier par ordre croissant toutes les balises town en fonction de la valeur de l'attribut name.

Pour cela, je vais dans un premier temps récupérer toutes les balises town.

>>> towns = xml.findAll('town')
>>> towns
[<town name="Paris"/>, <town name="Lyon"/>, <town name="Marseille"/>, <town name="Nantes"/>, <town name="Ancenis"/>, <town name="Bordeaux"/>, <town name="Toulouse"/>, <town name="Rouen"/>, <town name="Brest"/>]

Me voici donc avec une liste towns contenant toutes mes balises town.

Ensuite, je trie par ordre croissant le contenu de ma liste towns.

>>> towns.sort(key=lambda x: x.get('name'))
>>> towns
[<town name="Ancenis"/>, <town name="Bordeaux"/>, <town name="Brest"/>, <town name="Lyon"/>, <town name="Marseille"/>, <town name="Nantes"/>, <town name="Paris"/>, <town name="Rouen"/>, <town name="Toulouse"/>]

Pour trier correctement le contenu de ma liste, j'utilise le paramètre key de la fonction sort en y indiquant une fonction lambda dans laquelle je lui indique d'utiliser l'attribut name pour effectuer le tri.

Avec BeautifulSoup, pour obtenir la valeur d'un attribut d'une balise, il suffit d'utiliser la méthode get sur n'importe quel élément avec le nom de l'attribut, en l'occurence name.

Dans ma fonction lambda, x étant remplacé par chaque élément town de la liste.

Me voici donc avec ma liste parfaitement trié.

Il suffit donc maintenant de remplacer tout le contenu de la balise towns de mon XML avec le contenu de ma liste.

>>> xml.towns.clear()
>>> xml.towns
<towns/>
>>> xml.towns.extend(towns)
>>> print(xml.prettify())
<?xml version="1.0" encoding="utf-8"?>
<towns>
 <town name="Ancenis"/>
 <town name="Bordeaux"/>
 <town name="Brest"/>
 <town name="Lyon"/>
 <town name="Marseille"/>
 <town name="Nantes"/>
 <town name="Paris"/>
 <town name="Rouen"/>
 <town name="Toulouse"/>
</towns>

J'ai donc utilisé la méthode clear de l'élément towns pour vider tous les éléments town.

Enfin, comme pour une liste Python, la méthode extend de l'élément towns permet d'ajouter tout le contenu de la liste towns correctement triée.

Simple comme bonjour, isn't it....

Etiquettes: