Cours
Tutoriel XML en Python avec ElementTree : Guide du débutant
Exécutez et modifiez le code de ce tutoriel en ligne
Exécuter le codeEn tant que data scientist, vous découvrirez que la compréhension du XML est très utile pour le web-scraping et la pratique générale de l'analyse syntaxique d'un document structuré.
- Vous en apprendrez plus sur XML et vous découvrirez le paquetage Python
ElementTree
. - Ensuite, vous découvrirez comment vous pouvez explorer les arbres XML pour mieux comprendre les données avec lesquelles vous travaillez à l'aide des fonctions
ElementTree
, des boucles for et des expressions XPath. - Ensuite, vous apprendrez comment modifier un fichier XML.
- Vous utiliserez également des expressions xpath pour remplir des fichiers XML.
Apprenez Python à partir de zéro
Qu'est-ce que le XML ?
XML est l'abréviation de "Extensible Markup Language" (langage de balisage extensible). Il est principalement utilisé dans les pages web, où les données ont une structure spécifique et sont comprises dynamiquement par le cadre XML.
XML crée une structure arborescente qui est facile à interpréter et qui supporte une hiérarchie. Chaque fois qu'une page suit le langage XML, elle peut être appelée un document XML.
- Les documents XML comportent des sections appelées éléments, qui sont définies par une balise de début et une balise de fin. Une balise est une construction de balisage qui commence par
<
et se termine par>
. Les caractères entre la balise de début et la balise de fin, s'il y en a, constituent le contenu de l'élément. Les éléments peuvent contenir des balises, y compris d'autres éléments, appelés "éléments enfants". - L'élément le plus grand, de niveau supérieur, est appelé la racine, qui contient tous les autres éléments.
- Les attributs sont des paires nom-valeur qui existent dans une balise start-tag ou empty-element. Un attribut XML ne peut avoir qu'une seule valeur et chaque attribut ne peut apparaître qu'une seule fois sur chaque élément.
Pour mieux comprendre, jetez un coup d'œil au fichier XML (abrégé) suivant :
<?xml version="1.0"?>
<collection>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back 2 the Future">
<format multiple="False">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
</genre>
<genre category="Thriller">
<decade years="1970s">
<movie favorite="False" title="ALIEN">
<format multiple="Yes">DVD</format>
<year>1979</year>
<rating>R</rating>
<description>"""""""""</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="True" title="Ferris Bueller's Day Off">
<format multiple="No">DVD</format>
<year>1986</year>
<rating>PG13</rating>
<description>Funny movie about a funny guy</description>
</movie>
<movie favorite="FALSE" title="American Psycho">
<format multiple="No">blue-ray</format>
<year>2000</year>
<rating>Unrated</rating>
<description>psychopathic Bateman</description>
</movie>
</decade>
</genre>
D'après ce que vous avez lu ci-dessus, vous constatez que
est l'élément racine unique : il contient tous les autres éléments, tels que
, ou
, qui sont les éléments enfants ou les sous-éléments. Comme vous pouvez le constater, ces éléments sont imbriqués les uns dans les autres.
Notez que ces éléments enfants peuvent également agir en tant que parents et contenir leurs propres éléments enfants, qui sont alors appelés "éléments sous-enfants".
- Vous verrez que, par exemple, l'élément
contient quelques "attributs", tels que
favorite
title
, qui donnent encore plus d'informations !
Avec cette brève introduction aux fichiers XML en tête, vous êtes prêt à en apprendre davantage sur ElementTree
!
Introduction à ElementTree
La structure arborescente XML rend la navigation, la modification et la suppression relativement simples par programmation. Python dispose d'une bibliothèque intégrée, ElementTree
, qui contient des fonctions permettant de lire et de manipuler les fichiers XML (et d'autres fichiers structurés de manière similaire).
Tout d'abord, importez ElementTree
. Il est courant d'utiliser l'alias ET
:
import xml.etree.ElementTree as ET
Analyse des données XML
Le fichier XML fourni décrit une collection de base de films. Le seul problème, c'est que les données sont désordonnées ! Cette collection a été conservée par de nombreux conservateurs différents, et chacun a sa propre façon d'entrer les données dans le fichier. L'objectif principal de ce tutoriel sera de lire et de comprendre le fichier avec Python, puis de résoudre les problèmes.
Tout d'abord, vous devez lire le fichier à l'aide de ElementTree
.
tree = ET.parse('movies.xml')
root = tree.getroot()
Maintenant que vous avez initialisé l'arbre, vous devriez regarder le XML et imprimer les valeurs afin de comprendre comment l'arbre est structuré.
Chaque partie d'un arbre (y compris la racine) possède une balise qui décrit l'élément. En outre, comme vous l'avez vu dans l'introduction, les éléments peuvent avoir des attributs, qui sont des descripteurs supplémentaires utilisés en particulier pour l'utilisation répétée des balises. Les attributs permettent également de valider les valeurs saisies pour cette balise, ce qui contribue à nouveau au format structuré d'un XML.
Vous verrez plus loin dans ce tutoriel que les attributs peuvent être très puissants lorsqu'ils sont inclus dans un XML !
root.tag
'collection'
Au niveau supérieur, vous voyez que ce XML est ancré dans la balise collection
.
root.attrib
{}
La racine n'a donc pas d'attributs.
Pour les boucles
Vous pouvez facilement itérer sur les sous-éléments (communément appelés "enfants") de la racine en utilisant une simple boucle "for".
for child in root:
print(child.tag, child.attrib)
genre {'category': 'Action'}
genre {'category': 'Thriller'}
genre {'category': 'Comedy'}
Vous savez maintenant que les enfants de la racine collection
sont tous genre
. Pour désigner le genre, le XML utilise l'attribut category
. Il y a des films d'action, des thrillers et des comédies selon l'élément genre
.
En règle générale, il est utile de connaître tous les éléments de l'arbre complet. Une fonction utile pour ce faire est root.iter()
. Vous pouvez placer cette fonction dans une boucle "for" et elle parcourra l'ensemble de l'arbre.
[elem.tag for elem in root.iter()]
['collection',
'genre',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'genre',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'genre',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description',
'decade',
'movie',
'format',
'year',
'rating',
'description']
Cela donne une idée générale du nombre d'éléments que vous avez, mais ne montre pas les attributs ou les niveaux de l'arbre.
Il existe un moyen utile de consulter l'ensemble du document. Tout élément dispose d'une méthode .tostring()
. Si vous transmettez la racine à la méthode .tostring()
, vous pouvez renvoyer le document entier. À l'intérieur de ElementTree
(dont on se souvient qu'il est aliasé ET
), .tostring()
prend une forme un peu étrange.
Puisque ElementTree
est une bibliothèque puissante qui peut interpréter bien plus que du XML. Vous devez spécifier l'encodage et le décodage du document que vous affichez en tant que chaîne. Pour les XML, utilisez 'utf8'
- Il s'agit du format de document typique pour un XML.
print(ET.tostring(root, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<collection>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back 2 the Future">
<format multiple="False">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
</genre>
<genre category="Thriller">
<decade years="1970s">
<movie favorite="False" title="ALIEN">
<format multiple="Yes">DVD</format>
<year>1979</year>
<rating>R</rating>
<description>"""""""""</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="True" title="Ferris Bueller's Day Off">
<format multiple="No">DVD</format>
<year>1986</year>
<rating>PG13</rating>
<description>Funny movie about a funny guy</description>
</movie>
<movie favorite="FALSE" title="American Psycho">
<format multiple="No">blue-ray</format>
<year>2000</year>
<rating>Unrated</rating>
<description>psychopathic Bateman</description>
</movie>
</decade>
</genre>
<genre category="Comedy">
<decade years="1960s">
<movie favorite="False" title="Batman: The Movie">
<format multiple="Yes">DVD,VHS</format>
<year>1966</year>
<rating>PG</rating>
<description>What a joke!</description>
</movie>
</decade>
<decade years="2010s">
<movie favorite="True" title="Easy A">
<format multiple="No">DVD</format>
<year>2010</year>
<rating>PG--13</rating>
<description>Emma Stone = Hester Prynne</description>
</movie>
<movie favorite="True" title="Dinner for SCHMUCKS">
<format multiple="Yes">DVD,digital,Netflix</format>
<year>2011</year>
<rating>Unrated</rating>
<description>Tim (Rudd) is a rising executive
who “succeeds” in finding the perfect guest,
IRS employee Barry (Carell), for his boss’ monthly event,
a so-called “dinner for idiots,” which offers certain
advantages to the exec who shows up with the biggest buffoon.
</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="False" title="Ghostbusters">
<format multiple="No">Online,VHS</format>
<year>1984</year>
<rating>PG</rating>
<description>Who ya gonna call?</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Robin Hood: Prince of Thieves">
<format multiple="No">Blu_Ray</format>
<year>1991</year>
<rating>Unknown</rating>
<description>Robin Hood slaying</description>
</movie>
</decade>
</genre>
</collection>
Vous pouvez étendre l'utilisation de la fonction iter()
pour vous aider à trouver des éléments particuliers qui vous intéressent. root.iter()
énumère tous les sous-éléments sous la racine qui correspondent à l'élément spécifié. Ici, vous listerez tous les attributs de l'élément movie
dans l'arbre :
for movie in root.iter('movie'):
print(movie.attrib)
{'favorite': 'True', 'title': 'Indiana Jones: The raiders of the lost Ark'}
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'Back 2 the Future'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'True', 'title': "Ferris Bueller's Day Off"}
{'favorite': 'FALSE', 'title': 'American Psycho'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Easy A'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
{'favorite': 'False', 'title': 'Ghostbusters'}
{'favorite': 'True', 'title': 'Robin Hood: Prince of Thieves'}
Vous pouvez d'ores et déjà constater que les movies
ont été saisis de différentes manières. Ne vous inquiétez pas pour l'instant. Vous aurez l'occasion de corriger l'une des erreurs plus loin dans ce tutoriel.
Expressions XPath
Souvent, les éléments n'ont pas d'attributs, ils n'ont qu'un contenu textuel. En utilisant l'attribut .text
, vous pouvez imprimer ce contenu.
Imprimez maintenant toutes les descriptions des films.
for description in root.iter('description'):
print(description.text)
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
None provided.
Marty McFly
Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.
NA.
WhAtEvER I Want!!!?!
"""""""""
Funny movie about a funny guy
psychopathic Bateman
What a joke!
Emma Stone = Hester Prynne
Tim (Rudd) is a rising executive
who “succeeds” in finding the perfect guest,
IRS employee Barry (Carell), for his boss’ monthly event,
a so-called “dinner for idiots,” which offers certain
advantages to the exec who shows up with the biggest buffoon.
Who ya gonna call?
Robin Hood slaying
Imprimer le XML est utile, mais XPath est un langage de requête utilisé pour rechercher rapidement et facilement dans un XML. XPath est l'acronyme de XML Path Language et utilise, comme son nom l'indique, une syntaxe de type "chemin" pour identifier et parcourir les nœuds d'un document XML.
Comprendre XPath est d'une importance cruciale pour l'analyse et le remplissage des XML. ElementTree
possède une fonction .findall()
qui parcourt les enfants immédiats de l'élément référencé. Vous pouvez utiliser des expressions XPath pour spécifier des recherches plus utiles.
Ici, vous rechercherez dans l'arbre les films qui sont sortis en 1992 :
for movie in root.findall("./genre/decade/movie/[year='1992']"):
print(movie.attrib)
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
La fonction .findall()
commence toujours à l'élément spécifié. Ce type de fonction est extrêmement puissant pour une "recherche et un remplacement". Vous pouvez même effectuer des recherches sur les attributs !
Maintenant, n'imprimez que les films qui sont disponibles en plusieurs formats (un attribut).
for movie in root.findall("./genre/decade/movie/format/[@multiple='Yes']"):
print(movie.attrib)
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
{'multiple': 'Yes'}
Réfléchissez à la raison pour laquelle, dans ce cas, l'instruction print renvoie les valeurs "Oui" de multiple
. Réfléchissez à la manière dont la boucle "for" est définie. Pourriez-vous réécrire cette boucle pour imprimer les titres des films à la place ? Essayez-le ci-dessous :
Conseil: utilisez '...'
à l'intérieur de XPath pour renvoyer l'élément parent de l'élément actuel.
for movie in root.findall("./genre/decade/movie/format[@multiple='Yes']..."):
print(movie.attrib)
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
Modifier un fichier XML
Auparavant, les titres des films étaient un véritable fouillis. Maintenant, imprimez-les à nouveau :
for movie in root.iter('movie'):
print(movie.attrib)
{'favorite': 'True', 'title': 'Indiana Jones: The raiders of the lost Ark'}
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'Back 2 the Future'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'True', 'title': "Ferris Bueller's Day Off"}
{'favorite': 'FALSE', 'title': 'American Psycho'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Easy A'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
{'favorite': 'False', 'title': 'Ghostbusters'}
{'favorite': 'True', 'title': 'Robin Hood: Prince of Thieves'}
Corrigez le "2" dans Retour vers le futur. Cela devrait être un problème de recherche et de remplacement. Écrivez un code pour trouver le titre "Retour vers le futur" et l'enregistrer en tant que variable :
b2tf = root.find("./genre/decade/movie[@title='Back 2 the Future']")
print(b2tf)
<Element 'movie' at 0x10ce00ef8>
Notez que la méthode .find()
renvoie un élément de l'arbre. La plupart du temps, il est plus utile de modifier le contenu d'un élément.
Modifiez l'attribut title
de la variable de l'élément Retour vers le futur pour qu'il se lise "Retour vers le futur". Ensuite, imprimez les attributs de votre variable pour voir votre changement. Vous pouvez facilement le faire en accédant à l'attribut d'un élément et en lui attribuant une nouvelle valeur :
b2tf.attrib["title"] = "Back to the Future"
print(b2tf.attrib)
{'favorite': 'False', 'title': 'Back to the Future'}
Rédigez vos modifications dans le fichier XML afin qu'elles soient fixées de manière permanente dans le document. Imprimez à nouveau les attributs de votre film pour vous assurer que vos modifications ont bien été prises en compte. Pour ce faire, utilisez la méthode .write()
:
tree.write("movies.xml")
tree = ET.parse('movies.xml')
root = tree.getroot()
for movie in root.iter('movie'):
print(movie.attrib)
{'favorite': 'True', 'title': 'Indiana Jones: The raiders of the lost Ark'}
{'favorite': 'True', 'title': 'THE KARATE KID'}
{'favorite': 'False', 'title': 'Back to the Future'}
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'True', 'title': 'Batman Returns'}
{'favorite': 'False', 'title': 'Reservoir Dogs'}
{'favorite': 'False', 'title': 'ALIEN'}
{'favorite': 'True', 'title': "Ferris Bueller's Day Off"}
{'favorite': 'FALSE', 'title': 'American Psycho'}
{'favorite': 'False', 'title': 'Batman: The Movie'}
{'favorite': 'True', 'title': 'Easy A'}
{'favorite': 'True', 'title': 'Dinner for SCHMUCKS'}
{'favorite': 'False', 'title': 'Ghostbusters'}
{'favorite': 'True', 'title': 'Robin Hood: Prince of Thieves'}
Fixation des attributs
L'attribut multiple
est incorrect à certains endroits. Utilisez ElementTree
pour fixer l'identifiant en fonction du nombre de formats du film. Tout d'abord, imprimez l'attribut et le texte de format
pour voir quelles parties doivent être corrigées.
for form in root.findall("./genre/decade/movie/format"):
print(form.attrib, form.text)
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,Online
{'multiple': 'False'} Blu-ray
{'multiple': 'Yes'} dvd, digital
{'multiple': 'No'} VHS
{'multiple': 'No'} Online
{'multiple': 'Yes'} DVD
{'multiple': 'No'} DVD
{'multiple': 'No'} blue-ray
{'multiple': 'Yes'} DVD,VHS
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,digital,Netflix
{'multiple': 'No'} Online,VHS
{'multiple': 'No'} Blu_Ray
Il y a du travail à faire sur cette étiquette.
Vous pouvez utiliser des expressions rationnelles pour trouver des virgules, qui vous indiqueront si l'attribut multiple
doit être "Oui" ou "Non". L'ajout et la modification d'attributs peuvent être effectués facilement avec la méthode .set()
.
Remarque: re
est l'interpréteur de regex standard pour Python. Si vous souhaitez en savoir plus sur les expressions régulières, consultez ce tutoriel.
import re
for form in root.findall("./genre/decade/movie/format"):
# Search for the commas in the format text
match = re.search(',',form.text)
if match:
form.set('multiple','Yes')
else:
form.set('multiple','No')
# Write out the tree to the file again
tree.write("movies.xml")
tree = ET.parse('movies.xml')
root = tree.getroot()
for form in root.findall("./genre/decade/movie/format"):
print(form.attrib, form.text)
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,Online
{'multiple': 'No'} Blu-ray
{'multiple': 'Yes'} dvd, digital
{'multiple': 'No'} VHS
{'multiple': 'No'} Online
{'multiple': 'No'} DVD
{'multiple': 'No'} DVD
{'multiple': 'No'} blue-ray
{'multiple': 'Yes'} DVD,VHS
{'multiple': 'No'} DVD
{'multiple': 'Yes'} DVD,digital,Netflix
{'multiple': 'Yes'} Online,VHS
{'multiple': 'No'} Blu_Ray
Éléments mobiles
Certaines données ont été placées dans la mauvaise décennie. Utilisez ce que vous avez appris sur XML et ElementTree
pour trouver et corriger les erreurs de données de la décennie.
Il sera utile d'imprimer les balises decade
et year
tout au long du document.
for decade in root.findall("./genre/decade"):
print(decade.attrib)
for year in decade.findall("./movie/year"):
print(year.text, '\n')
{'years': '1980s'}
1981
1984
1985
{'years': '1990s'}
2000
1992
1992
{'years': '1970s'}
1979
{'years': '1980s'}
1986
2000
{'years': '1960s'}
1966
{'years': '2010s'}
2010
2011
{'years': '1980s'}
1984
{'years': '1990s'}
1991
Les deux années qui se situent dans la mauvaise décennie sont les films des années 2000. Déterminez la nature de ces films à l'aide d'une expression XPath.
for movie in root.findall("./genre/decade/movie/[year='2000']"):
print(movie.attrib)
{'favorite': 'False', 'title': 'X-Men'}
{'favorite': 'FALSE', 'title': 'American Psycho'}
Vous devez ajouter une nouvelle étiquette de décennie, les années 2000, au genre Action afin de déplacer les données X-Men. La méthode .SubElement()
peut être utilisée pour ajouter cette balise à la fin du XML.
action = root.find("./genre[@category='Action']")
new_dec = ET.SubElement(action, 'decade')
new_dec.attrib["years"] = '2000s'
print(ET.tostring(action, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back to the Future">
<format multiple="No">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
<decade years="2000s" /></genre>
Ajoutez maintenant le film X-Men aux années 2000 et retirez-le des années 1990, en utilisant respectivement .append()
et .remove()
.
xmen = root.find("./genre/decade/movie[@title='X-Men']")
dec2000s = root.find("./genre[@category='Action']/decade[@years='2000s']")
dec2000s.append(xmen)
dec1990s = root.find("./genre[@category='Action']/decade[@years='1990s']")
dec1990s.remove(xmen)
print(ET.tostring(action, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back to the Future">
<format multiple="No">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
<decade years="2000s"><movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
</decade></genre>
Construire des documents XML
Vous avez donc réussi à déplacer un film entier dans une nouvelle décennie. Enregistrez vos modifications dans le fichier XML.
tree.write("movies.xml")
tree = ET.parse('movies.xml')
root = tree.getroot()
print(ET.tostring(root, encoding='utf8').decode('utf8'))
<?xml version='1.0' encoding='utf8'?>
<collection>
<genre category="Action">
<decade years="1980s">
<movie favorite="True" title="Indiana Jones: The raiders of the lost Ark">
<format multiple="No">DVD</format>
<year>1981</year>
<rating>PG</rating>
<description>
'Archaeologist and adventurer Indiana Jones
is hired by the U.S. government to find the Ark of the
Covenant before the Nazis.'
</description>
</movie>
<movie favorite="True" title="THE KARATE KID">
<format multiple="Yes">DVD,Online</format>
<year>1984</year>
<rating>PG</rating>
<description>None provided.</description>
</movie>
<movie favorite="False" title="Back to the Future">
<format multiple="No">Blu-ray</format>
<year>1985</year>
<rating>PG</rating>
<description>Marty McFly</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Batman Returns">
<format multiple="No">VHS</format>
<year>1992</year>
<rating>PG13</rating>
<description>NA.</description>
</movie>
<movie favorite="False" title="Reservoir Dogs">
<format multiple="No">Online</format>
<year>1992</year>
<rating>R</rating>
<description>WhAtEvER I Want!!!?!</description>
</movie>
</decade>
<decade years="2000s"><movie favorite="False" title="X-Men">
<format multiple="Yes">dvd, digital</format>
<year>2000</year>
<rating>PG-13</rating>
<description>Two mutants come to a private academy for their kind whose resident superhero team must
oppose a terrorist organization with similar powers.</description>
</movie>
</decade></genre>
<genre category="Thriller">
<decade years="1970s">
<movie favorite="False" title="ALIEN">
<format multiple="No">DVD</format>
<year>1979</year>
<rating>R</rating>
<description>"""""""""</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="True" title="Ferris Bueller's Day Off">
<format multiple="No">DVD</format>
<year>1986</year>
<rating>PG13</rating>
<description>Funny movie about a funny guy</description>
</movie>
<movie favorite="FALSE" title="American Psycho">
<format multiple="No">blue-ray</format>
<year>2000</year>
<rating>Unrated</rating>
<description>psychopathic Bateman</description>
</movie>
</decade>
</genre>
<genre category="Comedy">
<decade years="1960s">
<movie favorite="False" title="Batman: The Movie">
<format multiple="Yes">DVD,VHS</format>
<year>1966</year>
<rating>PG</rating>
<description>What a joke!</description>
</movie>
</decade>
<decade years="2010s">
<movie favorite="True" title="Easy A">
<format multiple="No">DVD</format>
<year>2010</year>
<rating>PG--13</rating>
<description>Emma Stone = Hester Prynne</description>
</movie>
<movie favorite="True" title="Dinner for SCHMUCKS">
<format multiple="Yes">DVD,digital,Netflix</format>
<year>2011</year>
<rating>Unrated</rating>
<description>Tim (Rudd) is a rising executive
who “succeeds” in finding the perfect guest,
IRS employee Barry (Carell), for his boss’ monthly event,
a so-called “dinner for idiots,” which offers certain
advantages to the exec who shows up with the biggest buffoon.
</description>
</movie>
</decade>
<decade years="1980s">
<movie favorite="False" title="Ghostbusters">
<format multiple="Yes">Online,VHS</format>
<year>1984</year>
<rating>PG</rating>
<description>Who ya gonna call?</description>
</movie>
</decade>
<decade years="1990s">
<movie favorite="True" title="Robin Hood: Prince of Thieves">
<format multiple="No">Blu_Ray</format>
<year>1991</year>
<rating>Unknown</rating>
<description>Robin Hood slaying</description>
</movie>
</decade>
</genre>
</collection>
Quoi de neuf dans ElementTree ?
Voici un aperçu des nouvelles fonctionnalités et des améliorations apportées à la bibliothèque ElementTree dans les nouvelles versions de Python :
1. Prise en charge de XPath 1.0 (Python 3.8) : À partir de Python 3.8, ElementTree intègre la prise en charge complète de XPath 1.0 avec les méthodes find()
et findall()
, ce qui permet des requêtes XML plus riches et plus complexes. Exemple :
# Finding all movies with a specific attribute using XPath
for movie in root.findall(".//movie[@favorite='True']"):
print(movie.attrib)
2. Amélioration des espaces de noms (Python 3.8+) : Prise en charge améliorée des espaces de noms XML, permettant une interaction plus directe avec les fichiers XML qui utilisent des espaces de noms préfixés ou par défaut. Exemple :
# Register a namespace and find elements using it
ET.register_namespace('', 'http://example.com/namespace')
movies = root.findall(".//{http://example.com/namespace}movie")
3. Amélioration du parseur (Python 3.9) : L'amélioration de l'analyse des messages d'erreur facilite le débogage des fichiers XML malformés.
4. Nouvelle fonction indent()
(Python 3.9) : La fonction xml.etree.ElementTree.indent()
a été ajoutée pour imprimer des documents XML en indentant leurs éléments. Exemple :
ET.indent(root, space=" ", level=0)
ET.dump(root)
5. Parsing efficace avec iterparse
(Python 3.10) : Optimisé pour l'efficacité de la mémoire, particulièrement utile lorsque vous travaillez avec des fichiers XML volumineux.
6. Documentation élargie (mises à jour permanentes) : La documentation Python pour ElementTree est désormais plus complète, notamment en ce qui concerne les meilleures pratiques et les cas d'utilisation avancés.
Fonctionnalités obsolètes d'ElementTree et alternatives
1. write() avec xml_declaration en Python 3.8+ : Le paramètre xml_declaration
de la méthode write()
est obsolète lorsque l'encodage est réglé sur 'unicode'
.
- Alternative : N'utilisez
xml_declaration
que lorsque l'encodage est explicitement défini comme autre chose que'unicode'
.
tree.write("output.xml", encoding="utf-8", xml_declaration=True)
2. analyseur html : Bien qu'elle ne soit pas officiellement dépréciée, l'utilisation d'ElementTree pour l'analyse du code HTML est déconseillée, car elle est limitée dans la gestion du code HTML non correctement formé.
- Alternative : Utilisez des bibliothèques spécialement conçues pour l'analyse HTML, telles que
BeautifulSoup
du paquetbs4
.
from bs4 import BeautifulSoup soup = BeautifulSoup(html_content, 'html.parser')
3. Solutions de contournement pour la gestion des espaces de noms : Les anciennes méthodes de gestion manuelle des espaces de noms (par exemple, la concaténation des URI d'espaces de noms avec les balises d'éléments) sont moins recommandées depuis l'introduction d'une prise en charge robuste des espaces de noms dans les versions les plus récentes.
- Alternative : Utilisez les méthodes et fonctions intégrées tenant compte de l'espace de noms.
ET.register_namespace('', 'http://example.com/namespace') movies = root.findall(".//{http://example.com/namespace}movie")
4. Impression manuelle de jolies images : Les techniques manuelles d'indentation et de formatage du XML ont été rendues obsolètes par la nouvelle fonction indent()
(Python 3.9).
- Alternative : Utilisez
ET.indent()
pour le formatage automatique de XML.
ET.indent(root, space=" ")
5. Utilisation directe de _ElementInterface : Les classes internes telles que _ElementInterface
ne sont pas destinées à une utilisation directe et pourraient être interrompues dans les versions futures.
- Alternative : Interagissez toujours avec l'API publique documentée de la bibliothèque ElementTree.
Conclusion
Il y a quelques points essentiels à retenir à propos des XML et de l'utilisation de ElementTree
.
Les balises construisent l'arborescence et désignent les valeurs qui doivent y être délimitées. L'utilisation d'une structuration intelligente peut faciliter la lecture et l'écriture d'un XML. Les balises ont toujours besoin de parenthèses ouvrantes et fermantes pour indiquer les relations parents-enfants.
Les attributs décrivent en outre comment valider une balise ou permettent des désignations booléennes. Les attributs prennent généralement des valeurs très spécifiques afin que l'analyseur XML (et l'utilisateur) puisse utiliser les attributs pour vérifier les valeurs des balises.
ElementTree
est une bibliothèque Python importante qui vous permet d'analyser et de naviguer dans un document XML. L'utilisation de ElementTree
permet de décomposer le document XML en une structure arborescente facile à manipuler. En cas de doute, imprimez-le (print(ET.tostring(root, encoding='utf8').decode('utf8'))
) - utilisez cette déclaration d'impression utile pour visualiser l'ensemble du document XML en une seule fois. Il est utile de le vérifier lorsque vous modifiez, ajoutez ou supprimez des éléments d'un fichier XML.
Vous êtes maintenant en mesure de comprendre le XML et de commencer à l'analyser !
Devenez développeur Python

FAQ
Quels sont les cas d'utilisation courants de XML dans le domaine de la science des données ?
XML est souvent utilisé en science des données pour l'échange de données entre systèmes, le web scraping, les fichiers de configuration et le traitement de données ayant une structure hiérarchique complexe. Il est particulièrement utile lorsque vous travaillez avec des API qui renvoient des données XML.
ElementTree peut-il traiter efficacement des fichiers XML volumineux ?
ElementTree est adapté à la gestion de fichiers XML de taille modérée, mais pour les fichiers très volumineux, vous pouvez envisager d'utiliser des bibliothèques telles que lxml
ou xml.sax
qui sont plus économes en mémoire et qui peuvent traiter des fichiers volumineux en continu.
Comment ElementTree se compare-t-il à d'autres bibliothèques d'analyse XML comme lxml ou minidom ?
ElementTree fait partie de la bibliothèque standard de Python et est facile à utiliser pour les tâches d'analyse XML de base. lxml
ElementTree est plus puissant et plus rapide, et offre des fonctionnalités supplémentaires telles que la prise en charge de XPath 2.0. minidom
ElementTree, une autre bibliothèque standard, est basé sur le modèle d'objet de document (DOM) et est moins efficace pour les documents volumineux.
Que sont les expressions XPath et comment sont-elles utiles dans l'analyse syntaxique XML ?
Les expressions XPath sont des langages de requête permettant de sélectionner des nœuds dans un document XML. Ils sont utiles pour naviguer dans les éléments et les attributs des documents XML, ce qui permet de récupérer et de manipuler des données avec précision.
Comment puis-je valider un document XML avant de l'analyser avec ElementTree ?
Les documents XML peuvent être validés à l'aide d'une définition de schéma XML (XSD) ou d'une définition de type de document (DTD). Les bibliothèques Python telles que lxml
offrent une prise en charge intégrée de la validation par rapport à ces normes.
Quelles sont les meilleures pratiques pour modifier des données XML à l'aide d'ElementTree ?
Les meilleures pratiques consistent à travailler sur une copie des données XML afin d'éviter toute perte accidentelle de données, à utiliser des expressions XPath pour une navigation précise et à s'assurer que toutes les modifications maintiennent la bonne forme du document XML.
ElementTree peut-il être utilisé pour convertir des données XML en JSON ?
Bien qu'ElementTree ne fournisse pas de conversion directe de XML à JSON, vous pouvez analyser les données XML dans un dictionnaire Python à l'aide d'ElementTree, puis convertir le dictionnaire en JSON à l'aide du module Python json
de Python.
Comment gérez-vous les espaces de noms XML avec ElementTree ?
ElementTree peut gérer les espaces de noms XML en utilisant le préfixe{namespace}
dans les noms de balises. Vous pouvez également enregistrer des espaces de noms à l' adresse ET.register_namespace()
pour faciliter la gestion des espaces de noms XML.
Que dois-je faire si je rencontre une erreur d'analyse XML dans ElementTree ?
Vérifiez les problèmes courants tels que les fichiers XML malformés, les encodages non pris en charge ou les chemins d'accès incorrects. Utilisez les mécanismes de traitement des erreurs de Python ( blocstry-except
) pour diagnostiquer et gérer les erreurs d'analyse avec élégance.
Est-il possible d'imprimer un document XML en utilisant ElementTree ?
ElementTree ne prend pas directement en charge l'impression jolie, mais vous pouvez utiliser xml.dom.minidom
pour analyser la chaîne XML, puis utiliser sa méthode toprettyxml()
pour formater le XML afin de le rendre plus lisible.
En savoir plus sur Python
Cours
Python intermédiaire
Cours