Как обновить/изменить XML файл в python?

У меня есть документ XML, который я хотел бы обновить после того, как он уже содержит данные.

Я думал об открытии XML файла в режиме "a" (append). Проблема в том, что новые данные будут записаны после тега закрытия корня.

Как удалить последнюю строку файла, затем начать запись данных с этой точки, а затем закрыть корневой тег?

Конечно, я мог бы прочитать весь файл и сделать некоторые строковые манипуляции, но я не думаю, что лучшая идея..

Спасибо за ваше время.

Ответы

Ответ 1

Быстрый и простой способ, который вы определенно не должны делать (см. ниже), состоит в том, чтобы прочитать весь файл в списке строк, используя 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)

Причина, по которой вы не должны этого делать, состоит в том, что, если вы не делаете что-то очень быстрое n 'грязное, вы должны использовать XML-анализы. Это библиотека, которая позволяет работать с XML разумно, используя такие понятия, как DOM, деревья и узлы. Это не только правильный способ работы с XML, но и стандартный способ, который делает ваш код более переносимым и понятным для других программистов.

В ответе Тима упоминается проверка http://docs.python.org/library/xml.dom.minidom.html для этой цели, которая, я думаю, была бы отличной идеей.

Ответ 2

Использование 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')

note: вывод, записанный на 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 и т.д.) разница между этими двумя файлами может выглядеть не очень хорошо.

Ответ 3

Полезные парсеры XML Python:

  • Minidom - функциональный, но ограниченный
  • ElementTree - достойная производительность, большая функциональность
  • lxml - высокая производительность в большинстве случаев, высокая функциональность, включая реальную поддержку xpath

Любой из них лучше, чем пытаться обновить XML файл в виде строк текста.

Что это значит для вас:

Откройте ваш файл с помощью синтаксического анализатора XML по вашему выбору, найдите интересующий вас node, замените значение, выполните сериализацию файла.

Ответ 4

Пока я согласен с Тимом и Обеном Зонном, что вы должны использовать библиотеку 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()

Ответ 5

Что вы действительно хотите сделать, так это использовать парсер XML и добавить новые элементы с предоставленным API.

Затем просто перезапишите файл.

Самый простой в использовании, вероятно, будет парсер DOM, такой как ниже:

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

Ответ 6

Чтобы сделать этот процесс более надежным, вы можете рассмотреть использование анализатора SAX (таким образом, вам не нужно хранить весь файл в памяти), читать и писать до конца дерева, а затем начинать добавление.

Ответ 7

Вы должны прочитать XML файл, используя определенные модули XML. Таким образом, вы можете редактировать XML-документ в памяти и переписать измененный XML-документ в файл.

Вот быстрый старт: http://docs.python.org/library/xml.dom.minidom.html

Существует множество других утилит XML, которые лучше всего зависят от характера вашего XML файла и того, каким образом вы хотите его редактировать.

Ответ 8

Как объяснил Эдам Маор, быстрый и грязный способ сделать это (для [utc-16] закодированных файлов .xml), которые вы должны не делать для резонов, которые объяснил Эдам Маор, можно сделать со следующим кодом python 2.7, если временные ограничения не позволяют вам изучать (propper) 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.