75 votes

Quel est le moyen le plus rapide d’analyser des documents XML volumineux en Python?

Je suis actuellement le code suivant basé sur le chapitre 12.5 du livre de recettes Python:

 from xml.parsers import expat

class Element(object):
    def __init__(self, name, attributes):
        self.name = name
        self.attributes = attributes
        self.cdata = ''
        self.children = []
    def addChild(self, element):
        self.children.append(element)
    def getAttribute(self,key):
        return self.attributes.get(key)
    def getData(self):
        return self.cdata
    def getElements(self, name=''):
        if name:
            return [c for c in self.children if c.name == name]
        else:
            return list(self.children)

class Xml2Obj(object):
    def __init__(self):
        self.root = None
        self.nodeStack = []
    def StartElement(self, name, attributes):
        element = Element(name.encode(), attributes)
        if self.nodeStack:
            parent = self.nodeStack[-1]
            parent.addChild(element)
        else:
            self.root = element
        self.nodeStack.append(element)
    def EndElement(self, name):
        self.nodeStack.pop()
    def CharacterData(self,data):
        if data.strip():
            data = data.encode()
            element = self.nodeStack[-1]
            element.cdata += data
    def Parse(self, filename):
        Parser = expat.ParserCreate()
        Parser.StartElementHandler = self.StartElement
        Parser.EndElementHandler = self.EndElement
        Parser.CharacterDataHandler = self.CharacterData
        ParserStatus = Parser.Parse(open(filename).read(),1)
        return self.root
 

Je travaille avec des documents XML d'environ 1 Go. Est-ce que quelqu'un connaît un moyen plus rapide d'analyser ces?

79voto

Steen Points 3427

Je me semble que si vous n'avez pas besoin DOM capacités de votre programme. Je voudrais deuxième l'utilisation de l' (c)ElementTree de la bibliothèque. Si vous utilisez le iterparse fonction de la cElementTree module, vous pouvez travailler votre chemin à travers le xml et de traiter les événements comme ils se produisent.

À noter toutefois, Fredriks conseils sur l'utilisation de cElementTree iterparse fonction:

pour analyser les fichiers volumineux, vous pouvez vous débarrasser des éléments dès que vous avez traitées:

pour l'événement, elem dans iterparse(source):
 si elem.tag == "enregistrer":
 ... processus d'enregistrement des éléments ...
elem.clear()

Le schéma ci-dessus a un inconvénient; elle n'efface pas l'élément racine, de sorte que vous finirez avec un élément unique avec beaucoup de vide éléments enfants. Si vos fichiers sont énormes, plutôt que de vastes, ce pourrait être un problème. Pour contourner ce problème, vous devez obtenir vos mains sur l'élément racine. La façon la plus simple de le faire est d'activer les événements de démarrage, et de garder une référence vers le premier élément dans une variable:

# obtenir un objet iterable
contexte = iterparse(source, les événements=("début", "fin"))

# le transformer en un itérateur
contexte = iter(contexte)

# obtenir l'élément racine
l'événement, racine = contexte.next()

pour l'événement, elem dans le contexte:
 si event == "fin" et elem.tag == "enregistrer":
 ... processus d'enregistrement des éléments ...
de la racine.clear()

Le lxml.iterparse() ne le permet pas.

17voto

bhadra Points 7255

Avez-vous essayé le module cElementTree?

cElementTree est inclus avec Python 2.5 et versions ultérieures, sous la forme xml.etree.cElementTree. Reportez-vous aux points de repère .

texte alternatif

11voto

Manuel Ceron Points 3568

Je vous recommande d'utiliser lxml, c'est un binding python pour la bibliothèque libxml2 qui est vraiment très rapide.

Dans mon expérience, libxml2 et les expatriés ont très similaire à la performance. Mais je préfère libxml2 (et lxml pour python), car il semble être plus activement développé et testé. Aussi libxml2 a plus de fonctionnalités.

lxml est principalement API compatible avec xml.programme etree.ElementTree. Et il y a une bonne documentation sur son site web.

7voto

Aaron Digulla Points 143830

Enregistrer les callbacks ralentit l'analyse énormément. [EDIT]C'est parce que le (rapide) du code C a pour invoquer l'interpréteur python qui n'est tout simplement pas aussi vite que C. Fondamentalement, vous utilisez le code C pour lire le fichier (rapide) et ensuite construire le DOM en Python (lent).[/EDIT]

Essayez d'utiliser le format xml.programme etree.ElementTree qui est mis en œuvre à 100% en C et qui peut analyser XML, sans les rappels de code python.

Après que le document a été analysé, vous pouvez le filtrer pour obtenir ce que vous voulez.

Si c'est encore trop lent et vous n'avez pas besoin d'un DOM à l'autre option est de lire le fichier en une chaîne de caractères et utiliser de simples opérations de la chaîne à traiter.

5voto

Matt Campbell Points 788

Si votre demande est des performances sensibles et susceptibles de rencontrer de gros fichiers (comme vous l'avez dit, > 1 GO) alors que j'avais fortement déconseillé d'utiliser le code dont vous faites preuve dans votre question pour la simple raison qu' il charge l'intégralité du document dans la mémoire vive. Je vous encourage à repenser votre dessin (si possible) pour éviter de tenir l'ensemble de l'arborescence du document dans la mémoire RAM à la fois. Ne sachant pas ce que les exigences de votre application sont, je ne peux pas correctement suggérer une approche spécifique, autre que le générique morceau de conseils pour essayer d'utiliser un "événement" basée sur la conception.

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