Traitement XML en Python
Traitement XML avec Python
Section titled “Traitement XML avec Python”XML (eXtensible Markup Language) est un langage de balisage conçu pour stocker et transporter des données dans un format à la fois lisible par l’homme et lisible par la machine. Il est largement utilisé dans les fichiers de configuration, l’échange de données et les formats de documents.
Qu’est-ce que le XML ?
Section titled “Qu’est-ce que le XML ?”XML définit un ensemble de règles pour l’encodage des documents. Il utilise des balises (comme le HTML) pour définir des éléments et des attributs pour fournir des métadonnées sur ces éléments. Contrairement au HTML, XML ne prédéfinit pas les balises ; les utilisateurs définissent leurs propres balises pertinentes pour leurs données.
Caractéristiques Clés :
- Extensible : Vous définissez vos propres balises.
- Hiérarchique : Les données sont structurées sous forme d’arbre.
- Basé sur du texte : Utilise des caractères Unicode.
- Auto-descriptif : Les balises décrivent souvent les données qu’elles contiennent.
- Indépendant de la plateforme/du langage : Un standard ouvert.
Bien que JSON soit devenu plus populaire pour les API web en raison de sa simplicité et de sa correspondance directe avec les objets JavaScript, XML reste important pour de nombreux systèmes d’entreprise, les standards de documents (comme DocBook, Office Open XML) et la configuration.
API d’Analyse XML de Python
Section titled “API d’Analyse XML de Python”La bibliothèque standard de Python fournit plusieurs modules pour travailler avec XML, prenant en charge différentes stratégies d’analyse :
xml.etree.ElementTree: (Recommandé pour la plupart des tâches courantes) Fournit un moyen simple et “Pythonique” d’analyser et de créer du XML. Il charge l’intégralité du document dans une structure arborescente en mémoire (similaire au DOM) mais offre une API plus légère et souvent plus facile à utiliser.xml.dom.minidom: Implémente l’API Document Object Model (DOM), un standard du W3C. Il analyse l’intégralité du document XML en un arbre d’objets en mémoire, permettant un accès et une modification complets. Peut être gourmand en mémoire pour de très gros fichiers.xml.sax: Implémente le Simple API for XML (SAX), un analyseur basé sur les événements. Il lit le fichier XML séquentiellement, déclenchant des fonctions de rappel (handlers) pour des événements comme les balises de début, les balises de fin et les données de caractères. Il est efficace en mémoire car il ne charge pas le document entier, ce qui le rend adapté aux très grands fichiers ou au traitement en flux, mais peut être plus complexe à utiliser pour un accès aléatoire.
Choisir une API :
- Pour l’analyse et la création XML générales, commencez par
ElementTree. - Si vous avez besoin d’une conformité DOM stricte ou de modifications complexes de l’arbre, utilisez
minidom. - Pour traiter de très gros fichiers XML avec une mémoire limitée, utilisez
SAX.
Exemple de Fichier XML (movies.xml)
Section titled “Exemple de Fichier XML (movies.xml)”Nous utiliserons le fichier XML suivant pour les exemples :
<?xml version="1.0" encoding="UTF-8"?><collection shelf="New Arrivals"> <movie title="Enemy Behind"> <type>War, Thriller</type> <format>DVD</format> <year>2003</year> <rating>PG</rating> <stars>10</stars> <description>Talk about a US-Japan war</description> </movie> <movie title="Transformers"> <type>Anime, Science Fiction</type> <format>DVD</format> <year>1989</year> <rating>R</rating> <stars>8</stars> <description>A scientific fiction</description> </movie> <movie title="Trigun"> <type>Anime, Action</type> <format>DVD</format> <episodes>4</episodes> <rating>PG</rating> <stars>10</stars> <description>Vash the Stampede!</description> </movie> <movie title="Ishtar"> <type>Comedy</type> <format>VHS</format> <rating>PG</rating> <stars>2</stars> <description>Viewable boredom</description> </movie></collection>Analyse XML avec ElementTree (Recommandé)
Section titled “Analyse XML avec ElementTree (Recommandé)”ElementTree représente le document XML comme un arbre d’objets Element.
Exemple :
Section titled “Exemple :”#!/usr/bin/env python3
import xml.etree.ElementTree as ET
xml_file = 'movies.xml'
try: tree = ET.parse(xml_file) root = tree.getroot() # Obtenir l'élément racine ('collection')
print(f"Root element: {root.tag}, Shelf: {root.get('shelf')}")
# Iterate through 'movie' elements under the root for movie in root.findall('movie'): # findall trouve les enfants directs title = movie.get('title') # Obtenir la valeur de l'attribut year_element = movie.find('year') # find obtient le premier enfant correspondant type_element = movie.find('type')
# Le contenu textuel de l'élément est dans l'attribut .text movie_type = type_element.text if type_element is not None else 'N/A' year = year_element.text if year_element is not None else 'N/A'
print(f"\nMovie Title: {title}") print(f" Type: {movie_type}") print(f" Year: {year}")
# Accéder aux éléments potentiellement manquants en toute sécurité episodes_element = movie.find('episodes') if episodes_element is not None: print(f" Episodes: {episodes_element.text}")
except ET.ParseError as e: print(f"Erreur d'analyse XML : {e}")except FileNotFoundError: print(f"Erreur : Le fichier '{xml_file}' est introuvable.")Sortie :
Root element: collection, Shelf: New Arrivals
Movie Title: Enemy Behind Type: War, Thriller Year: 2003
Movie Title: Transformers Type: Anime, Science Fiction Year: 1989
Movie Title: Trigun Type: Anime, Action Year: N/A Episodes: 4
Movie Title: Ishtar Type: Comedy Year: N/AConcepts Clés d’ElementTree :
ET.parse(source): Analyse le XML à partir d’un chemin de fichier ou d’un objet de type fichier.ET.fromstring(text): Analyse le XML à partir d’une chaîne de caractères.tree.getroot(): Renvoie l’élément racine de l’arbre analysé.element.tag: Le nom de la balise de l’élément (chaîne de caractères).element.attrib: Un dictionnaire des attributs de l’élément.element.text: Le contenu textuel directement à l’intérieur de l’élément.element.get(attr_name): Obtient la valeur d’un attribut.element.find(match): Trouve le premier élément enfant direct correspondant au nom de balise ou au chemin.element.findall(match): Trouve tous les éléments enfants directs correspondant au nom de balise ou au chemin.element.iter(tag): Crée un itérateur sur tous les sous-éléments (directs et imbriqués) correspondant à la balise.
Analyse XML avec DOM (minidom)
Section titled “Analyse XML avec DOM (minidom)”minidom analyse le XML en une structure d’arbre DOM standard.
Exemple :
Section titled “Exemple :”#!/usr/bin/env python3
from xml.dom import minidomimport xml.parsers.expat # Souvent nécessaire pour attraper des erreurs d'analyse spécifiques
xml_file = 'movies.xml'
try: # Analyser le fichier XML en un arbre DOM dom_tree = minidom.parse(xml_file)
# Obtenir l'élément collection (racine) collection = dom_tree.documentElement # L'élément racine <collection>
if collection.hasAttribute("shelf"): print(f"Root element: <{collection.tagName}>, Shelf: {collection.getAttribute('shelf')}")
# Obtenir tous les éléments 'movie' movies = collection.getElementsByTagName("movie")
# Afficher les détails de chaque film for movie in movies: print("\n***** Film *****") if movie.hasAttribute("title"): print(f"Title: {movie.getAttribute('title')}")
# Fonction utilitaire pour obtenir le texte du premier élément enfant def get_element_text(parent, tag_name): elements = parent.getElementsByTagName(tag_name) if elements and elements[0].firstChild: # Vérifier si firstChild existe et est un nœud de texte if elements[0].firstChild.nodeType == elements[0].TEXT_NODE: return elements[0].firstChild.data.strip() return 'N/A'
print(f"Type: {get_element_text(movie, 'type')}") print(f"Format: {get_element_text(movie, 'format')}") print(f"Rating: {get_element_text(movie, 'rating')}") print(f"Description: {get_element_text(movie, 'description')}")
except xml.parsers.expat.ExpatError as e: print(f"Erreur d'analyse XML : {e}")except FileNotFoundError: print(f"Erreur : Le fichier '{xml_file}' est introuvable.")except Exception as e: print(f"Une erreur inattendue est survenue : {e}")Sortie (similaire à ElementTree, démontre l’accès DOM) :
Root element: <collection>, Shelf: New Arrivals
***** Film *****Title: Enemy BehindType: War, ThrillerFormat: DVDRating: PGDescription: Talk about a US-Japan war
***** Film *****Title: TransformersType: Anime, Science FictionFormat: DVDRating: RDescription: A scientific fiction...Concepts Clés du DOM :
minidom.parse(source): Analyse le XML.dom.documentElement: Le nœud d’élément racine.element.tagName: Nom de la balise de l’élément.element.getAttribute(name): Obtient la valeur de l’attribut.element.hasAttribute(name): Vérifie si l’attribut existe.element.getElementsByTagName(name): Obtient une liste de tous les éléments descendants avec le nom de balise donné.node.firstChild,node.childNodes,node.parentNode: Navigation à travers l’arbre.node.nodeType: Type de nœud (ELEMENT_NODE, TEXT_NODE, etc.).node.data: Contenu textuel d’un TEXT_NODE.
Analyse XML avec SAX (xml.sax)
Section titled “Analyse XML avec SAX (xml.sax)”L’analyse SAX nécessite la création d’une classe ‘Content Handler’ qui définit les méthodes à appeler lorsque l’analyseur rencontre des structures XML spécifiques (balises de début/fin, données de caractères).
Exemple :
Section titled “Exemple :”#!/usr/bin/env python3
import xml.sax
# Définir la classe Content Handlerclass MovieHandler(xml.sax.ContentHandler): def __init__(self): super().__init__() self.current_data = "" # Stocke le nom de la balise en cours de traitement self.type = "" self.format = "" self.year = "" self.rating = "" self.stars = "" self.description = "" self.episodes = "" # Ajouté pour Trigun self.current_movie_title = ""
# Appelé lorsqu'un élément commence def startElement(self, tag, attributes): self.current_data = tag if tag == "movie": print("\n***** Film *****") self.current_movie_title = attributes.get("title", "N/A") print(f"Title: {self.current_movie_title}") # Réinitialiser les champs spécifiques au film self.type = self.format = self.year = self.rating = "" self.stars = self.description = self.episodes = ""
# Appelé lorsqu'un élément se termine def endElement(self, tag): if tag == "type": print(f" Type: {self.type}") elif tag == "format": print(f" Format: {self.format}") elif tag == "year": print(f" Year: {self.year}") elif tag == "rating": print(f" Rating: {self.rating}") elif tag == "stars": print(f" Stars: {self.stars}") elif tag == "description": print(f" Description: {self.description}") elif tag == "episodes": print(f" Episodes: {self.episodes}")
# Réinitialiser le suivi de la balise actuelle self.current_data = ""
# Appelé avec les données de caractères entre les balises def characters(self, content): # Ne stocker le contenu que si c'est à l'intérieur d'une balise pertinente if self.current_data == "type": self.type += content.strip() elif self.current_data == "format": self.format += content.strip() elif self.current_data == "year": self.year += content.strip() elif self.current_data == "rating": self.rating += content.strip() elif self.current_data == "stars": self.stars += content.strip() elif self.current_data == "description": self.description += content.strip() elif self.current_data == "episodes": self.episodes += content.strip()
# --- Exécution principale ---xml_file = 'movies.xml'
# Créer un analyseur SAXparser = xml.sax.make_parser()# Désactiver les espaces de noms (optionnel, simplifie l'exemple)parser.setFeature(xml.sax.handler.feature_namespaces, 0)
# Créer une instance de notre gestionnairehandler = MovieHandler()# Définir le gestionnaire pour l'analyseurparser.setContentHandler(handler)
print("--- Début de l'analyse SAX ---")try: parser.parse(xml_file) print("\n--- Analyse SAX Terminée ---")except xml.sax.SAXParseException as e: print(f"Erreur d'analyse SAX : {e}")except FileNotFoundError: print(f"Erreur : Le fichier '{xml_file}' est introuvable.")Sortie (contenu similaire, flux de traitement différent) :
--- Début de l'analyse SAX ---
***** Film *****Title: Enemy Behind Type: War, Thriller Format: DVD Year: 2003 Rating: PG Stars: 10 Description: Talk about a US-Japan war
***** Film *****Title: Transformers...Concepts Clés de SAX :
xml.sax.make_parser(): Crée un objet analyseur SAX.xml.sax.ContentHandler: Classe de base pour la gestion des événements d’analyse.startElement(tag, attributes): Appelé pour chaque balise ouvrante.endElement(tag): Appelé pour chaque balise fermante.characters(content): Appelé avec des fragments de données de caractères entre les balises.parser.setContentHandler(handler): Associe votre gestionnaire à l’analyseur.parser.parse(source): Démarre le processus d’analyse.
Génération XML
Section titled “Génération XML”ElementTree est également pratique pour créer des documents XML.
import xml.etree.ElementTree as ET
# Créer l'élément racineroot = ET.Element("data")
# Créer des éléments enfantsitem1 = ET.SubElement(root, "item")item1.set("name", "item1_name") # Définir l'attributitem1.text = "This is the first item."
item2 = ET.SubElement(root, "item", attrib={"name": "item2_name", "type": "testing"})item2.text = "Second item content."
# Créer un arbre et écrire dans un fichiertree = ET.ElementTree(root)
# Formatage joli (optionnel, ajoute l'indentation)ET.indent(tree, space=" ", level=0)
try: tree.write("output.xml", encoding="utf-8", xml_declaration=True) print("Fichier output.xml généré")except IOError as e: print(f"Erreur lors de l'écriture du fichier XML : {e}")