【问题标题】:How to write into a preexisting xml file while maintaining the structure?如何在保持结构的同时写入预先存在的 xml 文件?
【发布时间】:2019-08-01 18:53:08
【问题描述】:

我正在尝试编写此错误检查器,如果文件名已经存在,则将数据写入该文件。理想情况下,我希望 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,而不是写入文件。我该如何更改?

【问题讨论】:

    标签: python xml file-io


    【解决方案1】:

    如果您打算将新数据附加到文件中,您可以通过向写入函数提供文件对象而不是名称来实现,如文档所述:

    将元素树以 XML 格式写入文件。 file 是文件名,或 为写入而打开的文件对象。

    https://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree.write

    # ab for append binary, as stated in https://stackoverflow.com/questions/37713184/python-element-tree-writing-to-new-file
    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' 的子标签并将其返回。文本将获取其内容。如果 xml 格式不正确,它可能没有标签名称,在这种情况下,它会抛出一个 'TypeError',所以我们跳过迭代。

    这是一个带有 if-else 的版本:

    if country.find('name') == None:
        continue
    
    name = country.find('name').text
    

    如果你确定你的 xml 格式正确,你可以像这样简单地完成这部分:

    name = country.find('name').text
    

    你不需要修改其余代码,只需要修改try-catch的这一部分。

    【讨论】:

    • 我的意图是添加一个新的国家,如何追加而不覆盖文件(我不想失去第一个国家)?
    • 您介意解释一下您的 try/except 子句吗?抱歉,我对 try/except 没有太多经验。它究竟是做什么的?另外,变量 country 来自这个 try/except 短语中的迭代器,对吧?
    • 此外,我正在使用的 xml 文件没有任何属性,因此这可能是我在 try/except 子句中混淆的一部分(在我的问题中,我有一个 xml 文件的示例)正在使用)
    • 嘿,关于try catch它的工作原理是这样的:可能国家没有属性,在这种情况下,它会引发TypeError异常,如果有,那么我们跳过循环继续,我们进入下一次迭代。如果不是,则名称由本例中的属性给出。
    • 关于name属性,是的,它来自try catch,因为它可以引发异常。我可以先检查 country 是否有名字,如果没有,我们什么都不做,如果有,我们在 try-catch 之后做剩下的事情。
    猜你喜欢
    • 1970-01-01
    • 2020-06-03
    • 2012-08-20
    • 2020-02-19
    • 2018-11-01
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 2015-11-13
    相关资源
    最近更新 更多