Как обновить / изменить файл XML в python?
У меня есть XML-документ, который я хотел бы обновить после того, как он уже содержит данные.
Я думал об открытии файла XML в "a"
(добавить) режим. Проблема в том, что новые данные будут записаны после корневого закрывающего тега.
Как я могу удалить последнюю строку файла, затем начать запись данных с этой точки, а затем закрыть корневой тег?
Конечно, я мог прочитать весь файл и выполнить некоторые манипуляции со строками, но я не думаю, что это лучшая идея..
Спасибо за ваше время.
8 ответов
Быстрый и простой способ, который вам определенно не следует делать (см. Ниже), - это прочитать весь файл в список строк, используя readlines()
, Я пишу это на тот случай, если вы ищете быстрое и простое решение.
Просто откройте файл, используя open()
затем позвоните readlines()
метод. То, что вы получите, это список всех строк в файле. Теперь вы можете легко добавлять строки перед последним элементом (просто добавьте в список один элемент перед последним). Наконец, вы можете записать их обратно в файл, используя writelines()
,
Пример может помочь:
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)
Причина, по которой вам не следует этого делать, заключается в том, что, если вы не делаете что-то очень быстрое и грязное, вы должны использовать парсер XML. Это библиотека, которая позволяет вам интеллектуально работать с XML, используя такие понятия, как DOM, деревья и узлы. Это не только правильный способ работы с XML, это еще и стандартный способ, который делает ваш код более переносимым и более простым для понимания другими программистами.
В ответе Тима упоминается проверка xml.dom.minidom
для этой цели, что я думаю, было бы отличной идеей.
С помощью 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')
примечание: вывод записывается в file_new.xml
для экспериментов, пишите в file.xml
заменит старый контент.
ВАЖНО: библиотека ElementTree хранит атрибуты в dict, поэтому порядок, в котором эти атрибуты перечислены в тексте xml, НЕ будет сохранен. Вместо этого они будут выводиться в алфавитном порядке. (также, комментарии удалены. Я нахожу это довольно раздражающим)
т.е.: текстовый ввод XML <b y='xxx' x='2'>some body</b>
будет выводиться как <b x='2' y='xxx'>some body</b>
(после алфавитного определения определяются параметры заказа)
Это означает, что при фиксации оригинала и измененных файлов в системе контроля версий (например, SVN, CSV, ClearCase и т. Д.) Разница между двумя файлами может выглядеть не очень красиво.
Полезные парсеры Python XML:
- Минидом - функциональный, но ограниченный
- ElementTree - достойная производительность, больше функциональности
- lxml - высокая производительность в большинстве случаев, высокая функциональность, включая реальную поддержку xpath
Любой из них лучше, чем пытаться обновить файл XML в виде строк текста.
Что это значит для вас:
Откройте ваш файл с помощью анализатора XML по вашему выбору, найдите интересующий вас узел, замените значение, верните файл в исходное состояние.
Хотя я согласен с Тимом и Обеном Сонне в том, что вам следует использовать библиотеку XML, есть способы по-прежнему манипулировать ею как простым строковым объектом.
Я, вероятно, не буду пытаться использовать один указатель файла для того, что вы описываете, а вместо этого прочитать файл в память, отредактировать его, а затем выписать.
inFile = open('file.xml', 'r')
data = inFile.readlines()
inFile.close()
# some manipulation on `data`
outFile = open('file.xml', 'w')
outFile.writelines(data)
outFile.close()
Для модификации вы можете использовать
tag.text
из xml. Вот фрагмент:
import xml.etree.ElementTree as ET
tree = ET.parse('country_data.xml')
root = tree.getroot()
for rank in root.iter('rank'):
new_rank = int(rank.text) + 1
rank.text = str(new_rank)
tree.write('output.xml')
В
rank
в коде - пример тега, который зависит от содержимого вашего XML файла.
Что вы действительно хотите сделать, так это использовать синтаксический анализатор XML и добавлять новые элементы с предоставленным API.
Затем просто перезапишите файл.
Самым простым в использовании, вероятно, будет парсер DOM, подобный приведенному ниже:
Чтобы сделать этот процесс более устойчивым, вы можете использовать синтаксический анализатор SAX (таким образом, вам не нужно хранить весь файл в памяти), читать и писать до конца дерева, а затем начинать добавлять.
Как объяснил Эдан Маор, быстрый и грязный способ сделать это (для XML-файлов, закодированных в [utc-16]), который вы не должны делать для объяснений Эдама Маора, может быть выполнен с помощью следующего кода Python 2.7 в случае временных ограничений. не позволяют изучать (проппер) синтаксический анализ XML.
Предполагая, что вы хотите:
- Удалить последнюю строку в исходном XML-файле.
- Добавить строку
- подставить строку
- Закройте корневой тег.
Он работал в python 2.7, изменяя XML-файл с именем "b.xml", расположенный в папке "a", где "a" находился в "рабочей папке" python. Он выводит новый измененный файл как "c.xml" в папку "a", без ошибок кодирования (для меня) при дальнейшем использовании вне 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.
Вы должны прочитать файл XML, используя определенные модули XML. Таким образом, вы можете редактировать XML-документ в памяти и переписывать ваш измененный XML-документ в файл.
Вот быстрый старт: http://docs.python.org/library/xml.dom.minidom.html
Существует множество других утилит XML, которые лучше всего зависят от природы вашего XML-файла и способа его редактирования.