如何在保持结构的同时写入预先存在的 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。