89 votes

Analyse syntaxique XML - ElementTree vs SAX et DOM

Python a plusieurs façons d'analyser le XML...

Je comprends les bases de l'analyse syntaxique avec SAX . Il fonctionne comme un analyseur de flux, avec une API pilotée par les événements.

Je comprends que DOM également. Il lit le XML en mémoire et le convertit en objets auxquels on peut accéder avec Python.

D'une manière générale, il était facile de choisir entre les deux en fonction de ce que vous aviez besoin de faire, des contraintes de mémoire, des performances, etc.

(J'espère que j'ai raison jusqu'à présent.)

Depuis Python 2.5, nous avons également ElementTree . Comment cela se compare-t-il à DOM et SAX ? A quoi ressemble-t-il le plus ? Pourquoi est-il meilleur que les analyseurs précédents ?

84voto

Torsten Marek Points 27554

ElementTree est beaucoup plus facile à utiliser, car il représente un arbre XML (essentiellement) comme une structure de listes, et les attributs sont représentés comme des dictionnaires.

ElementTree a besoin de beaucoup moins de mémoire pour les arbres XML que DOM (et est donc plus rapide), et la surcharge de l'analyse syntaxique via iterparse est comparable à SAX. En outre, iterparse renvoie des structures partielles, et vous pouvez maintenir l'utilisation de la mémoire constante pendant l'analyse en éliminant les structures dès que vous les traitez.

ElementTree, comme dans Python 2.5, ne possède qu'un petit ensemble de fonctionnalités par rapport aux bibliothèques XML à part entière, mais c'est suffisant pour de nombreuses applications. Si vous avez besoin d'un analyseur de validation ou d'un support XPath complet, lxml est la solution. Pendant longtemps, elle a été assez instable, mais je n'ai pas eu de problèmes avec elle depuis la version 2.1.

ElementTree s'écarte du DOM, où les nœuds ont accès à leur parent et à leurs frères et sœurs. La gestion de documents réels plutôt que de magasins de données est également un peu lourde, car les nœuds de texte ne sont pas traités comme des nœuds réels. Dans l'extrait XML

<a>This is <b>a</b> test</a>

La chaîne test sera ce que l'on appelle tail de l'élément b .

En général, je recommande ElementTree comme valeur par défaut pour tout traitement XML avec Python, et DOM ou SAX comme solutions pour des problèmes spécifiques.

2 votes

Merci de mentionner les deux mises en garde suivantes ! (Il se trouve que j'ai besoin des deux dans mon projet.) "XPath support ... ElementTree s'écarte du DOM, où les nœuds ont accès à leur parent et à leurs frères et sœurs."

1 votes

ElementTree présente également le problème suivant : le contenu textuel est traité comme une propriété du nœud précédent, et non comme un nœud à part entière. Ainsi, dans "<p>Le <i>chien marron</i></p>", l'élément <p>a 1 enfant, et non 3. "Le" est une propriété sur le <p>, et "chien" est une propriété sur le <i> (même pas la même propriété -- il pourrait y avoir du texte juste après la fin du <p>, aussi). Presque tout ce qui concerne les arbres, les contextes, les chemins et la recherche fonctionne de manière très différente de ce à quoi vous êtes habitué si vous utilisez HTML, CSS ou presque tout ce qui a trait aux documents.

16voto

Paolo Rovelli Points 892

Mise en œuvre minimale de DOM :

Lien .

Python fournit une implémentation complète et standardisée par le W3C de XML DOM ( xml.dom ) et un autre, minimal, xml.dom.minidom . Cette dernière est plus simple et plus petite que l'implémentation complète. Cependant, du point de vue de l'analyse syntaxique, elle a tous les avantages et les inconvénients du DOM standard - c'est-à-dire qu'elle charge tout en mémoire.

Considérant un fichier XML de base :

<?xml version="1.0"?>
<catalog>
    <book isdn="xxx-1">
      <author>A1</author>
      <title>T1</title>
    </book>
    <book isdn="xxx-2">
      <author>A2</author>
      <title>T2</title>
    </book>
</catalog>

Un analyseur Python possible utilisant minidom est :

import os
from xml.dom import minidom
from xml.parsers.expat import ExpatError

#-------- Select the XML file: --------#
#Current file name and directory:
curpath = os.path.dirname( os.path.realpath(__file__) )
filename = os.path.join(curpath, "sample.xml")
#print "Filename: %s" % (filename)

#-------- Parse the XML file: --------#
try:
    #Parse the given XML file:
    xmldoc = minidom.parse(filepath)
except ExpatError as e:
    print "[XML] Error (line %d): %d" % (e.lineno, e.code)
    print "[XML] Offset: %d" % (e.offset)
    raise e
except IOError as e:
    print "[IO] I/O Error %d: %s" % (e.errno, e.strerror)
    raise e
else:
    catalog = xmldoc.documentElement
    books = catalog.getElementsByTagName("book")

    for book in books:
        print book.getAttribute('isdn')
        print book.getElementsByTagName('author')[0].firstChild.data
        print book.getElementsByTagName('title')[0].firstChild.data

Notez que xml.parsers.expat est une interface Python pour l'analyseur XML non validant Expat (docs.python.org/2/library/pyexpat.html).

Le site xml.dom Le paquet fournit également la classe d'exception DOMException mais il n'est pas supprimé dans minidom !

L'API XML ElementTree :

Lien .

ElementTree est beaucoup plus facile à utiliser et nécessite moins de mémoire que XML DOM. De plus, une implémentation en C est disponible ( xml.etree.cElementTree ).

Un analyseur Python possible utilisant ElementTree est :

import os
from xml.etree import cElementTree  # C implementation of xml.etree.ElementTree
from xml.parsers.expat import ExpatError  # XML formatting errors

#-------- Select the XML file: --------#
#Current file name and directory:
curpath = os.path.dirname( os.path.realpath(__file__) )
filename = os.path.join(curpath, "sample.xml")
#print "Filename: %s" % (filename)

#-------- Parse the XML file: --------#
try:
    #Parse the given XML file:
    tree = cElementTree.parse(filename)
except ExpatError as e:
    print "[XML] Error (line %d): %d" % (e.lineno, e.code)
    print "[XML] Offset: %d" % (e.offset)
    raise e
except IOError as e:
    print "[XML] I/O Error %d: %s" % (e.errno, e.strerror)
    raise e
else:
    catalogue = tree.getroot()

    for book in catalogue:
        print book.attrib.get("isdn")
        print book.find('author').text
        print book.find('title').text

2 votes

Merci ! Très utile. Je ne suis pas assez sûr pour l'éditer, mais je pense que (a) le reste n'est pas utile puisqu'il n'y a pas de conclusion : stackoverflow.com/questions/855759/python-try-else ; (b) un simple relèvement préserverait plus que le relèvement e : stackoverflow.com/questions/11420464/

0 votes

Concernant le point (a), oui. Il n'y a pas de déclaration finale simplement parce que, dans mon exemple, ce n'était pas nécessaire. Je ne me souviens pas pourquoi je l'ai mise. Cependant, même si elle est inutile dans ce cas, la présence de l'instruction else n'est pas syntaxiquement incorrecte.

0 votes

En ce qui concerne le point b), il pourrait en être ainsi. Cependant, je pense (dans mon exemple) que c'est un peu hors sujet. En effet, le code était censé n'être qu'un simple exemple de parsing XML...

10voto

iny Points 3925

ElementTree a une API plus pythique. Il fait également partie de la bibliothèque standard, ce qui permet de réduire les dépendances.

En fait, je préfère lxml car il dispose d'une API comme ElementTree, mais il a également de belles fonctionnalités supplémentaires et fonctionne bien.

7voto

sanxiyn Points 2704

La fonction parse() d'ElementTree ressemble à DOM, tandis que la fonction iterparse() ressemble à SAX. À mon avis, ElementTree est meilleur que DOM et SAX dans la mesure où il fournit une API plus facile à utiliser.

0 votes

De plus, je trouve que je veux la vraie structure, pas une série d'événements.

1 votes

Un analyseur sériel est souvent suffisant pour une analyse simple. J'ai commencé Python en utilisant sax, et je ne suis passé à minidom que lorsque mes besoins sont devenus trop complexes pour sax. Je dois ajouter que je n'ai pas encore utilisé ElementTree, car il ne semble pas offrir suffisamment de fonctionnalités supplémentaires pour que je porte mon code dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X