我有一个XML文档,想在它已经包含数据的情况下进行更新。
我考虑使用打开XML文件的"a"
(追加)模式。但问题是新数据将写在根闭合标签后面。
如何删除文件的最后一行,然后从那个位置开始写入数据,接着再关闭根标签呢?
当然,我可以读取整个文件并进行一些字符串操作,但我认为这不是最好的方法..
使用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等)时,两个文件之间的差异可能看起来并不美观。
ns0:previoustag
,为什么? - user2974951ns0
看起来像是一个命名空间,可以阅读 https://docs.python.org/2/library/xml.etree.elementtree.html#parsing-xml-with-namespaces 了解更多关于使用命名空间解析XML的信息。 - FraggaMuffin有用的Python XML解析器:
使用其中任何一个都比尝试将XML文件更新为文本字符串更好。
这对你意味着:
使用您选择的XML解析器打开文件,找到您感兴趣的节点,替换值,然后将文件序列化回来。
解决问题的一种简单而快捷的方式(下面会提到,您绝对不应该这样做)是使用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
以实现此目的,我认为这是个好主意。
虽然我同意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()
对于修改,您可以使用来自xml的tag.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文件内容。您真正想要做的是使用XML解析器,并使用提供的API附加新元素。
然后,简单地覆盖文件。
最简单使用的可能是像下面这个DOM解析器:
为了使这个过程更加健壮,您可以考虑使用SAX解析器(这样您就不必将整个文件保存在内存中),读取并写入整个树的末尾,然后开始附加。
正如Edan Maor所解释的那样,对于[utc-16]编码的.xml文件,可以采用快速而不太规范的方法来完成(但出于Edam Maor所解释的原因,您不应该这样做),如果时间紧迫,无法学习(适当的)XML解析器,则可以使用以下Python 2.7代码。
假设您想要:
它在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.