Как обновить / изменить файл 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:

  1. Минидом - функциональный, но ограниченный
  2. ElementTree - достойная производительность, больше функциональности
  3. 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, подобный приведенному ниже:

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

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

Как объяснил Эдан Маор, быстрый и грязный способ сделать это (для XML-файлов, закодированных в [utc-16]), который вы не должны делать для объяснений Эдама Маора, может быть выполнен с помощью следующего кода Python 2.7 в случае временных ограничений. не позволяют изучать (проппер) синтаксический анализ XML.

Предполагая, что вы хотите:

  1. Удалить последнюю строку в исходном XML-файле.
  2. Добавить строку
  3. подставить строку
  4. Закройте корневой тег.

Он работал в 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-файла и способа его редактирования.

Другие вопросы по тегам