如何在保持结构的同时写入预先存在的 xml 文件?
How to write into a preexisting xml file while maintaining the structure?
我正在尝试编写此错误检查程序,如果文件名已经存在,则将数据写入该文件。理想情况下,我希望 xml 文件看起来像这样:
<CONTACT_INFORMATION>
<DATA_RECORD>
<name>John</name>
<phone>1111111111</phone>
<email>something@gmail.com</email>
</DATA_RECORD>
<DATA_RECORD>
<name>Jane</name>
<phone>2222222222</phone>
<email>otherthing@gmail.com</email>
</DATA_RECORD>
</CONTACT_INFORMATION>
文件的名称是 INFO_John.xml 和 INFO_Jane.xml
这是我的代码目前的样子:
def information(listofdata):
root = et.Element('CONTACT_INFORMATION')
record = et.SubElement(root, 'DATA_RECORD')
et.SubElement(record, "name").text = listofdata[0]
et.SubElement(record, "phone").text = listofdata[1]
et.SubElement(record, "email").text = listofdata[2]
tree = et.ElementTree(root)
if os.path.exists(f"PERSON_{collected_data[0]}.xml") == True:
tree.write(f"INFO_{collected_data[0]}.xml")
else:
tree.write(f"INFO_{collected_data[0]}.xml")
然而,这只是覆盖原来的 INFO_John.xml 和 INFO_Jane.xml 而不是写入文件。我该如何更改?
如果您打算将新数据附加到文件中,您可以通过向写入函数提供文件对象而不是名称来实现,如文档所述:
Writes the element tree to a file, as XML. file is a file name, or a
file object opened for writing.
https://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree.write
# ab for append binary, as stated in
file = open(f"INFO_{collected_data[0]}.xml", "ab")
tree.write(file)
但是如果你不想追加而是想修改它,你将需要打开文件,修改结构并重新写入,用新文件覆盖文件。例如,假设我有一个像这样的 xml:
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
如果您打算添加一个新国家/地区,则必须打开该文件,向树中添加一个新国家/地区并覆盖该文件。第一个解决方案将逐字追加新数据,而忽略根。您也可以使用第一种方法并在执行之前删除根元素。处理完成后,再次添加根元素。
[编辑]
如果您的意图是在我的示例中添加一个新的国家/地区,一种方法是打开文件并将新元素添加到另一棵树中。
import xml.etree.ElementTree as ET
import os
tree = ET.parse('country.xml')
name = ''
# For all country at the tree
for country in tree.findall('country'):
# If country has no attribute name, skip
try:
name = country.attrib['name']
except TypeError:
continue
# File name format
file_name = '{}.xml'.format(name)
if os.path.exists(file_name):
# File exists, open it
temp = ET.parse(file_name)
root = temp.getroot()
# Preserving identation
root[-1].tail = '\n '
else:
# File doesn't exist, create new xml tree
root = ET.Element('data')
temp = ET.ElementTree(root)
root = temp.getroot()
# Preserving identation
root.text = '\n '
# Put the country in the tree
root.append(country)
# Preserving identation
country.tail = '\n'
temp.write(file_name)
[编辑 2]
使用您的回答示例,而不是这样做:
try:
name = country.attrib['name']
except TypeError:
continue
你会做这样的事情:
try:
name = country.find('name').text
except TypeError:
continue
Find name 将找到名为 'name' 和 return 的第一个子标签。文本将获取其内容。如果 xml 格式不正确,它可能没有标签名称,在这种情况下,它会抛出一个 'TypeError',所以我们跳过迭代。
这是一个带有 if-else 的版本:
if country.find('name') == None:
continue
name = country.find('name').text
如果你确定你的 xml 格式正确,你可以像这样简单地完成这部分:
name = country.find('name').text
您不需要修改其余代码,只需修改这部分try-catch。
我正在尝试编写此错误检查程序,如果文件名已经存在,则将数据写入该文件。理想情况下,我希望 xml 文件看起来像这样:
<CONTACT_INFORMATION>
<DATA_RECORD>
<name>John</name>
<phone>1111111111</phone>
<email>something@gmail.com</email>
</DATA_RECORD>
<DATA_RECORD>
<name>Jane</name>
<phone>2222222222</phone>
<email>otherthing@gmail.com</email>
</DATA_RECORD>
</CONTACT_INFORMATION>
文件的名称是 INFO_John.xml 和 INFO_Jane.xml
这是我的代码目前的样子:
def information(listofdata):
root = et.Element('CONTACT_INFORMATION')
record = et.SubElement(root, 'DATA_RECORD')
et.SubElement(record, "name").text = listofdata[0]
et.SubElement(record, "phone").text = listofdata[1]
et.SubElement(record, "email").text = listofdata[2]
tree = et.ElementTree(root)
if os.path.exists(f"PERSON_{collected_data[0]}.xml") == True:
tree.write(f"INFO_{collected_data[0]}.xml")
else:
tree.write(f"INFO_{collected_data[0]}.xml")
然而,这只是覆盖原来的 INFO_John.xml 和 INFO_Jane.xml 而不是写入文件。我该如何更改?
如果您打算将新数据附加到文件中,您可以通过向写入函数提供文件对象而不是名称来实现,如文档所述:
Writes the element tree to a file, as XML. file is a file name, or a file object opened for writing.
https://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree.write
# ab for append binary, as stated in
file = open(f"INFO_{collected_data[0]}.xml", "ab")
tree.write(file)
但是如果你不想追加而是想修改它,你将需要打开文件,修改结构并重新写入,用新文件覆盖文件。例如,假设我有一个像这样的 xml:
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
如果您打算添加一个新国家/地区,则必须打开该文件,向树中添加一个新国家/地区并覆盖该文件。第一个解决方案将逐字追加新数据,而忽略根。您也可以使用第一种方法并在执行之前删除根元素。处理完成后,再次添加根元素。
[编辑]
如果您的意图是在我的示例中添加一个新的国家/地区,一种方法是打开文件并将新元素添加到另一棵树中。
import xml.etree.ElementTree as ET
import os
tree = ET.parse('country.xml')
name = ''
# For all country at the tree
for country in tree.findall('country'):
# If country has no attribute name, skip
try:
name = country.attrib['name']
except TypeError:
continue
# File name format
file_name = '{}.xml'.format(name)
if os.path.exists(file_name):
# File exists, open it
temp = ET.parse(file_name)
root = temp.getroot()
# Preserving identation
root[-1].tail = '\n '
else:
# File doesn't exist, create new xml tree
root = ET.Element('data')
temp = ET.ElementTree(root)
root = temp.getroot()
# Preserving identation
root.text = '\n '
# Put the country in the tree
root.append(country)
# Preserving identation
country.tail = '\n'
temp.write(file_name)
[编辑 2]
使用您的回答示例,而不是这样做:
try:
name = country.attrib['name']
except TypeError:
continue
你会做这样的事情:
try:
name = country.find('name').text
except TypeError:
continue
Find name 将找到名为 'name' 和 return 的第一个子标签。文本将获取其内容。如果 xml 格式不正确,它可能没有标签名称,在这种情况下,它会抛出一个 'TypeError',所以我们跳过迭代。
这是一个带有 if-else 的版本:
if country.find('name') == None:
continue
name = country.find('name').text
如果你确定你的 xml 格式正确,你可以像这样简单地完成这部分:
name = country.find('name').text
您不需要修改其余代码,只需修改这部分try-catch。