Pour le XML, .sort() ou .sorted() ?

Pour trier les éléments d’un corpus XML selon un critère donné, on peut utiliser la fonction .sorted(), qui crée une nouvelle liste triée. En effet, puisque ce que renvoie Element.findall() est bien une liste, rien n’empêche de lui appliquer toutes les fonctions qui interagissent avec le type list.

Il devrait alors être possible d’utiliser .sort(), autre fonction native de Python, pour trier des (sous-)éléments dans une arborescence XML. Est-ce bien le cas ?

Bien sûr que oui, mais en raison des différences de fonctionnement entre .sorted() et .sort(), il faut légèrement adapter le code selon la fonction choisie.

Je recommande la lecture préalable de Trier des éléments XML par valeur d’attribut. Le présent article vient à la suite, et partage également le même script associé. Celui-ci est mis à disposition sur Github et Gitlab.

Voici un extrait de code permettant de trier les sous-éléments element de ce corpus XML sur la base de la valeur de leur attribut id avec .sorted() :

elements = root.findall("element")
elements_tries = sorted(elements, key=lambda element: int(element.attrib["id"]))
root[:] = elements_tries

La fonction est appliquée à la liste elements, et son résultat, qui est aussi une liste, est associé à la variable elements_tries1.

Pour utiliser .sort() plutôt que .sorted(), c’est cette partie du script qui sera à modifier2. Le point de départ reste le même, à savoir récupérer la liste des éléments element et l’associer à une variable.

elements = root.findall("element")

Comment trier cette liste avec .sort() et surtout, comment traiter le résultat obtenu pour modifier l’arborescence XML ? Si vous consultez la documentation Python consacrée aux fonction de tri, vous remarquerez que si .sorted() renvoie une liste, il se trouve que .sort() ne renvoie en fait rien du tout3.

Ainsi, si vous associez le résultat de .sort() à une variable, cette dernière contiendra None, ce qui n’est évidemment ni utile ni souhaitable. Voici comment appeler .sort() sur notre liste elements :

elements.sort(key=lambda element: int(element.attrib["id"]))

La syntaxe pour spécifier le critère de tri est la même qu’avec .sorted(), mais cette fois la liste elements ne fait pas partie des arguments. J’ai qualifié .sort() de “fonction” un peu plus haut, et je ne distingue pas systématiquement méthode et fonction dans mes articles, mais la raison est ici qu’en fait .sort() est une méthode de la classe list. En tant que telle, elle est à appliquer suivant la syntaxe instance_d_objet_list.sort().

Une autre conséquence de ce statut de méthode est que les changements opérés modifient directement la liste. Ce qui explique par ailleurs pourquoi .sort() renvoie None, et par extension pourquoi il ne faut pas associer son résultat à une nouvelle variable.

Dans l’exemple, la liste elements a directement été modifiée. S’agissant d’une liste de sous-éléments déjà placés dans l’arborescence XML4, il n’y pas pas besoin de remplacer le contenu de root. Si l’arborescence XML (root) est convertie en chaîne de caractères et écrite dans un fichier, les éléments element seront ordonnés suivant la valeur de leur attribut id comme dans cet exemple de fichier de sortie.

En résumé, dans le script fourni en exemple, en remplaçant :

elements = root.findall("element")
elements_tries = sorted(elements, key=lambda element: int(element.attrib["id"]))
root[:] = elements_tries

Par :

elements = root.findall("element")
elements.sort(key=lambda element: int(element.attrib["id"]))

On aboutit exactement au même résultat, en supposant que le reste du script n’a pas été modifié.

Pourquoi alors utiliser .sorted() et non .sort() qui est pourtant plus synthétique ? Il y a effectivement des cas où il est plus efficace de passer par .sort(). La différence à prendre en compte est que .sorted() permet de garder trace de l’ordre d’origine des (sous-)éléments XML, puisque la liste triée est associée à une nouvelle variable, sans écraser la liste non triée ; ceci dit, rien n’empêche de stocker une copie la liste d’origine dans une variable séparée avant d’effectuer le tri avec .sort().

Au final le choix repose avant tout sur vos préférences personnelles, et/ou celles des personnes qui seront amenées à travailler avec votre code.

Citer ce billet : “Pour le XML, .sort() ou .sorted() ?”, par Alexander Delaporte. Publié sur Tekipaki le 08/04/2022. Lien : https://tekipaki.hypotheses.org/2559.
  1. Vous trouverez ici des explications plus détaillées à propos de cet extrait de code. []
  2. Dans le script téléchargeable (sur Github ou Gitlab), l’extrait correspond aux lignes 21 à 23. []
  3. Ou, pour être plus exact, renvoie None. []
  4. Ce qui n’était pas le cas de le liste elements_tries obtenue via .sorted(), qui ne préexistait pas et n’était pas rattachée à la structure XML au moment de sa déclaration. []

Auteur/autrice : Alexander Delaporte

Ingénieur d'études au Centre de recherches linguistiques sur l'Asie Orientale

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.