如何在Python中更新/修改XML文件?

54

我有一个XML文档,想在它已经包含数据的情况下进行更新。

我考虑使用打开XML文件的"a"(追加)模式。但问题是新数据将写在根闭合标签后面。

如何删除文件的最后一行,然后从那个位置开始写入数据,接着再关闭根标签呢?

当然,我可以读取整个文件并进行一些字符串操作,但我认为这不是最好的方法..


当然,我可以读取唯一的文件和进行字符串操作。- 我不确定我理解了最后一部分,请您重新表述一下? - Edan Maor
9个回答

101

使用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库将属性存储在字典中,因此这些属性在xml文本中列出的顺序不会被保留。相反,它们将按字母顺序输出。 (另外,注释也被删除了。我发现这相当烦人)

例如:xml输入文本<b y='xxx' x='2'>some body</b>将输出为<b x='2' y='xxx'>some body</b>(在定义参数的顺序后,按字母表顺序排列)

这意味着,当提交原始文件和更改后的文件到版本控制系统(如SVN、CSV、ClearCase等)时,两个文件之间的差异可能看起来并不美观。


我使用Python2,当我打开一个XML文件并将其写入另一个文件时,所有标签都会更改为新标签ns0:previoustag,为什么? - user2974951
ns0看起来像是一个命名空间,可以阅读 https://docs.python.org/2/library/xml.etree.elementtree.html#parsing-xml-with-namespaces 了解更多关于使用命名空间解析XML的信息。 - FraggaMuffin
1
Python 3.6+ 现在保留字典顺序。 - Dionys

32

有用的Python XML解析器:

  1. Minidom - 功能有限但可用
  2. ElementTree - 性能良好,功能更多
  3. lxml - 大多数情况下性能卓越,具有高级功能包括真正的xpath支持

使用其中任何一个都比尝试将XML文件更新为文本字符串更好。

这对你意味着:

使用您选择的XML解析器打开文件,找到您感兴趣的节点,替换值,然后将文件序列化回来。


12

解决问题的一种简单而快捷的方式(下面会提到,您绝对不应该这样做)是使用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的正确方式,也是标准的方式,使你的代码更便携,并且更容易让其他程序员理解。

Tim的答案提到了检查xml.dom.minidom以实现此目的,我认为这是个好主意。


14
不使用解析器进行XML编辑是一种极不推荐的代码实现方式。我曾经不得不绕过其他人发布的这类软件,它非常丑陋。如果涉及到XML,则应该遵循一些特定属性,例如能够处理空格、移动标签但保持XML的语义意义,或添加XML注释等。这样做将使最终程序变得脆弱,可能会首先失败。请务必避免! - Paddy3118

4

虽然我同意Tim和Oben Sonne的建议,你应该使用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()

3

对于修改,您可以使用来自xmltag.text。这里是片段:

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文件内容。

2

2

为了使这个过程更加健壮,您可以考虑使用SAX解析器(这样您就不必将整个文件保存在内存中),读取并写入整个树的末尾,然后开始附加。


0
你应该使用特定的XML模块来读取XML文件。这样,你就可以在内存中编辑XML文档,并将更改后的XML文档重写到文件中。
以下是一个快速入门:http://docs.python.org/library/xml.dom.minidom.html 还有很多其他的XML工具,哪一个最好取决于你的XML文件的性质以及你想以哪种方式进行编辑。

0

正如Edan Maor所解释的那样,对于[utc-16]编码的.xml文件,可以采用快速而不太规范的方法来完成(但出于Edam Maor所解释的原因,您不应该这样做),如果时间紧迫,无法学习(适当的)XML解析器,则可以使用以下Python 2.7代码。

假设您想要:

  1. 删除原始xml文件中的最后一行。
  2. 添加一行
  3. 替换一行
  4. 关闭根标记。

它在python 2.7中运行良好,修改名为“b.xml”的.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.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接