web-dev-qa-db-fra.com

Comment mettre à jour/modifier un fichier XML en python?

J'ai un document XML que je voudrais mettre à jour après qu'il contient déjà des données.

J'ai pensé ouvrir le fichier XML en mode "a" (ajouter). Le problème est que les nouvelles données seront écrites après la balise de fermeture racine.

Comment puis-je supprimer la dernière ligne d'un fichier, puis commencer à écrire des données à partir de ce point et fermer la balise racine?

Bien sûr, je pourrais lire le fichier entier et faire quelques manipulations de chaîne, mais je ne pense pas que ce soit la meilleure idée.

Merci pour votre temps.

19
nunos

Le moyen rapide et facile, que vous devez absolument ne devriez pas faire (voir ci-dessous), consiste à lire le fichier entier dans une liste de chaînes à l'aide de readlines(). J'écris ceci au cas où la solution rapide et facile est ce que vous recherchez.

Ouvrez simplement le fichier en utilisant open(), puis appelez la méthode readlines(). Vous obtiendrez une liste de toutes les chaînes du fichier. Maintenant, vous pouvez facilement ajouter des chaînes avant le dernier élément (ajoutez simplement à la liste un élément avant le dernier). Enfin, vous pouvez les réécrire dans le fichier en utilisant writelines().

Un exemple pourrait aider:

my_file = open(filename, "r")
lines_of_file = my_file.readlines()
lines_of_file.insert(-1, "This line is added one before the last line")
my_file.writelines(lines_of_file)

La raison pour laquelle vous ne devriez pas le faire est que, sauf si vous faites quelque chose de très rapide, vous devriez utiliser un analyseur XML. C'est une bibliothèque qui vous permet de travailler avec XML de manière intelligente, en utilisant des concepts tels que DOM, les arbres et les nœuds. C’est non seulement la manière appropriée de travailler avec XML, mais aussi la méthode standard, ce qui rend votre code plus portable et plus facile à comprendre pour les autres programmeurs. 

La réponse de Tim a mentionné la vérification de xml.dom.minidom à cette fin, ce qui, à mon avis, serait une excellente idée.

6
Edan Maor

Utiliser ElementTree:

import xml.etree.ElementTree

# Open original file
et = xml.etree.ElementTree.parse('file.xml')

# Append new tag: <a x='1' y='abc'>body text</a>
new_tag = xml.etree.ElementTree.SubElement(et.getroot(), 'a')
new_tag.text = 'body text'
new_tag.attrib['x'] = '1' # must be str; cannot be an int
new_tag.attrib['y'] = 'abc'

# Write back to file
#et.write('file.xml')
et.write('file_new.xml')

remarque: la sortie écrite dans file_new.xml pour que vous puissiez l'expérimenter, la réécriture dans file.xml remplacera l'ancien contenu.

IMPORTANT: la bibliothèque ElementTree stocke les attributs dans un dict. Par conséquent, l'ordre dans lequel ces attributs sont répertoriés dans le texte XML ne sera PAS conservé. Au lieu de cela, ils seront affichés dans l'ordre alphabétique . (Les commentaires sont également supprimés. Je trouve cela plutôt gênant)

c'est-à-dire que le texte d'entrée XML <b y='xxx' x='2'>some body</b> sera affiché en tant que <b x='2' y='xxx'>some body</b> (après avoir défini l'ordre alphabétique, les paramètres de l'ordre sont définis)

Cela signifie que lors de la validation des fichiers originaux et des fichiers modifiés dans un système de contrôle de révision (tel que SVN, CSV, ClearCase, etc.), une différence entre les 2 fichiers peut ne pas sembler esthétique.

53
FraggaMuffin

Analyseurs XML Python utiles:

  1. Minidom - fonctionnel mais limité
  2. ElementTree - performances décentes, plus de fonctionnalités
  3. lxml - hautes performances dans la plupart des cas, fonctionnalités avancées, notamment prise en charge réelle de xpath

N'importe lequel de ces avantages vaut mieux que d'essayer de mettre à jour le fichier XML sous forme de chaînes de texte.

Qu'est-ce que cela signifie pour vous:

Ouvrez votre fichier avec un analyseur XML de votre choix, trouvez le nœud qui vous intéresse, remplacez la valeur, sérialisez le fichier.

20
Gabriel Hurley

Bien que je sois d’accord avec Tim et Oben Sonne pour utiliser une bibliothèque XML, il existe des moyens de la manipuler en tant qu’objet chaîne simple. 

Je n'essaierais probablement pas d'utiliser un pointeur de fichier unique pour ce que vous décrivez, mais de lire le fichier en mémoire, de le modifier, puis de l'écrire:

inFile = open('file.xml', 'r')
data = inFile.readlines()
inFile.close()
# some manipulation on `data`
outFile = open('file.xml', 'w')
outFile.writelines(data)
outFile.close()
3
John Paulett

Ce que vous voulez vraiment faire, c'est utiliser un analyseur XML et ajouter les nouveaux éléments avec l'API fournie.

Ensuite, écrasez simplement le fichier.

Le plus facile à utiliser serait probablement un analyseur DOM comme celui ci-dessous:

http://docs.python.org/library/xml.dom.minidom.html

1
Tim

Pour rendre ce processus plus robuste, vous pouvez envisager d'utiliser l'analyseur SAX (de cette manière, vous n'avez pas besoin de garder le fichier entier en mémoire), de lire et d'écrire jusqu'à la fin de l'arbre, puis de commencer à ajouter.

1
jldupont

Vous devriez lire le fichier XML en utilisant des modules XML spécifiques. De cette façon, vous pouvez éditer le document XML en mémoire et réécrire votre document XML modifié dans le fichier.

Voici un début rapide: http://docs.python.org/library/xml.dom.minidom.html

Il existe de nombreux autres utilitaires XML, lequel dépend le mieux de la nature de votre fichier XML et de la manière dont vous souhaitez l'éditer.

0
Oben Sonne

Comme Edan Maor l'a expliqué, la façon rapide et sale de le faire (pour les fichiers .xml codés avec [utc-16]), ce que vous devriez faire pas pour les raisons expliquées par Edam Maor, peut être réalisée avec le code python 2.7 suivant dans le cas où les contraintes de temps ne vous permettent pas d'apprendre (propper) XML analyser.

En supposant que vous vouliez: 

  1. Supprimer la dernière ligne du fichier XML d'origine. 
  2. Ajouter une ligne
  3. substituer une ligne
  4. Fermez la balise racine.

Cela fonctionnait en python 2.7 en modifiant un fichier .xml nommé "b.xml" situé dans le dossier "a", où "a" se trouvait dans le "dossier de travail" de python. Il génère le nouveau fichier modifié sous le nom "c.xml" dans le dossier "a", sans générer d'erreur de codage (pour moi), qui sera utilisé ultérieurement en dehors de Python 2.7.

pattern = '<Author>'
subst = '    <Author>' + domain + '\\' + user_name + '</Author>'
line_index =0 #set line count to 0 before starting
file = io.open('a/b.xml', 'r', encoding='utf-16')
lines = file.readlines()
outFile = open('a/c.xml', 'w')
for line in lines[0:len(lines)]:
    line_index =line_index +1
    if line_index == len(lines):
        #1. & 2. delete last line and adding another line in its place not writing it
        outFile.writelines("Write extra line here" + '\n')
        # 4. Close root tag:
        outFile.writelines("</phonebook>") # as in:
        #http://tizag.com/xmlTutorial/xmldocument.php
    else:
        #3. Substitue a line if it finds the following substring in a line:
        pattern = '<Author>'
        subst = '    <Author>' + domain + '\\' + user_name + '</Author>'
        if pattern in line:
            line = subst
            print line
        outFile.writelines(line)#just writing/copying all the lines from the original xml except for the last.
0
a.t.