Cela fait longtemps que JSON n'est pas devenu le courant dominant lors de l'échange de données lisibles par machine, mais les données sont parfois distribuées en XML (comme les données publiées par une ancienne institution).
Ou si vous effectuez un traitement en langage naturel, par exemple, l'analyseur de syntaxe CaboCha
a une option ( -f 3
) pour afficher le résultat de l'analyse au format XML, de sorte que le traitement du résultat est dans le format dit "treillis". Je pense que cela peut être utilisé dans le sens où ce sera plus facile.
Dans ce dernier cas, j'essayais de déposer le résultat de l'analyse syntaxique d'un gros corpus en XML, mais lorsque j'ai essayé de traiter le XML de 8 Go sur la machine avec 64 Go de mémoire à portée de main, la mémoire était pleine. Je suis resté coincé au milieu (je ne crache même pas d'erreur). J'ai été un peu surpris car je l'ai fait 64 Go avec l'intention de faire de mon mieux pour augmenter la mémoire.
Le XML en question se présente sous la forme d'une liste avec un certain nombre de balises «
<root>
<item>...</item>
<item>...</item>
...
<item>...</item>
</root>
Lors du traitement de chaque «élément», cela n'a rien à voir avec les autres «éléments», et il est bon de les regarder un par un. Beaucoup d'entre vous savent que l'utilisation de ʻiterator (générateur) est conviviale pour la mémoire lorsque ce type de données est énorme. Bien sûr, les bibliothèques qui gèrent XML ont aussi des méthodes qui permettent de lire les fichiers XML avec ʻiterator
, mais c'était un peu délicat.
Il est facile d'utiliser le standard xml.etree.ElementTree
lorsque vous travaillez avec XML en Python. Il existe aussi un fameux dokoro BeautifulSoup, mais il est analysé avec XML que je souhaite manipuler car il est spécialisé en HTML. Il y a une partie qui provoque une erreur [^ 1], et j'en suis accro, donc j'ai choisi la bibliothèque standard.
Cet article décrit les précautions à prendre lors de l'exécution de l'analyse XML ʻiteratoravec cette bibliothèque standard
xml`.
C'est le cas lorsque vous l'utilisez normalement sans utiliser ʻiterator`.
import xml.etree.ElementTree as ET
tree = ET.parse('path/to/xml')
for item in tree.iterfind('item'):
# do something on item
Vous lisez la balise <item>
dans l'arborescence XML avec .iterfind ()
while ʻiterator. Mais juste avant cela, ʻET.parse () ʻest comme
file.readlines () `. Je mange beaucoup de mémoire.
C'est à ce moment que vous voulez lire tout en ʻiter`.
import xml.etree.ElementTree as ET
context = ET.iterparse('path/to/xml')
for event, elem in context:
if elem.tag == 'item':
# do something on item
Si ʻET.parse () ʻest changé en ʻET.iterparse () , le XML dans le chemin d'argument sera lu au format ʻiterator
. Je l'ai lu tag par tag, mais context
renvoie ʻevent et ʻelem
uniquement lorsqu'il atteint la fin de la balise. ʻEvent == "end" et ʻelem
est un élément.
Maintenant, vous pouvez économiser de la mémoire! Si vous y réfléchissez, c'est une grosse erreur. En fait, même si # faire quelque chose sur l'élément
est pass
, il utilise autant de mémoire que ** "usage habituel" **.
** ʻiter, mais
context` enregistre toutes les balises que vous avez lues jusqu'à présent **.
Quelque part, une variable locale appelée context.root
est cachée à l'intérieur de l'itérateur. Je ne le savais pas car je ne l'ai même pas écrit dans la documentation officielle. Peut-être que certaines personnes sont heureuses dans le sens où elles peuvent être consultées à plusieurs reprises plus tard, contrairement au "générateur" habituel. Eh bien, je peux imaginer qu'un tel mécanisme est nécessaire pour lire et conserver la structure imbriquée de XML.
Alors, que dois-je faire? Conseils sur la page officielle avant qu'elle ne soit incorporée dans le standard de Python 2.5 en tant que bibliothèque nommée ʻElementTree` il y a longtemps. eu. Python était un nouveau venu de 3 donc je ne l'ai pas fait du tout.
import xml.etree.ElementTree as ET
context = ET.iterparse('path/to/xml', events=('start', 'end'))
_, root = next(context) #Allez un peu plus loin et obtenez root
for event, elem in context:
if event == 'end' and elem.tag == 'item':
# do something on item
root.clear() #Vider la racine lorsque vous avez terminé
Vous pouvez spécifier l'argument mot-clé ʻeventsdans ʻET.iterparse ()
, et si vous spécifiez 'start'
à ceci, il vous indiquera la balise d'ouverture. La première balise ouverte est «
Si vous prenez root
[^ 2], vous pouvez supprimer les informations d'élément de la mémoire par` .clear () ʻà chaque fois. Je suis heureux.
[^ 1]: Si une seule balise telle que «» réservée en HTML est utilisée en XML, même s'il y a du texte à l'intérieur, elle sera effacée. Il y avait probablement une solution de contournement, mais je me souviens que cela n'a pas fonctionné.
[^ 2]: Cela ressemble à Android il y a longtemps et c'est merveilleux.
Recommended Posts