【问题标题】:Replace xml value based on csv columns根据 csv 列替换 xml 值
【发布时间】:2021-09-23 05:41:44
【问题描述】:

我正在尝试根据 csv 列替换 xml 文件中的类名。其实xml文件就是注解文件。

这是xml的格式:

<annotation>
<folder>./test_xmls</folder>
<filename>000048_Panorama.jpg</filename>
<path>./images000048_Panorama.jpg</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>4000</width>
<height>2000</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>AAAA</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>

我的 csv 包含 original 列并更改为`列。

格式为:

|original | change to|
-------------------------- 
| AAAA  | class_A |

..................

Csv 有超过 20000 行,其中包括 80000 个 xml 文件中的所有 &lt;name&gt;AAAA&lt;/name&gt;。

我想将 xml 名称(如 AAAA)与 csv 列匹配。如果它存在于original 列中,那么我想用change to 中的相应值替换,比如AAAA 到class_A。

我尝试编写 python 代码,但它不起作用。 我的代码在这里

import xml.etree.ElementTree as ET
import os
import pandas as pd
from collections import defaultdict
import csv
from csv import reader


with open('table.csv', mode='r') as inp:
    reader = csv.reader(inp)
    dict_from_csv = {rows[0]:rows[2] for rows in reader}

#print(dict_from_csv)

root_path = "./xmls"

xml_list = sorted(os.listdir(root_path))

for xml_file in xml_list:
    xml_path = os.path.join(root_path,xml_file)
    # parse xml file
    tree = ET.parse(xml_path)
    # get root node
    root = tree.getroot()
    for member in root.findall('object'):
        sub_child = member[0].text
        print(sub_child)
    for key, value in dict_from_csv.items():
        if sub_child in key:
            sub_child = sub_child.replace(sub_child, value)
            #print(xml)
        xml_file.write(sub_child)  
        print("Classes are changed : " + xml_path)

任何帮助将不胜感激。

谢谢

【问题讨论】:

    标签: python python-3.x xml python-2.7 csv


    【解决方案1】:

    下面的代码应该做你想做的事:

    import lxml.html   # check https://pypi.org/project/lxml/
    from csv import reader
    from os.path import exists
    import glob
    
    
    def update_xml(path: str) -> None:
        with open('./convertions.csv', 'r') as convertions, open(path, 'r') as annotation:  # noqa: E501
            tree = lxml.html.fromstring(annotation.read())
            csv_reader = reader(convertions)
    
            for idx, row in enumerate(csv_reader, start=1):
                if idx == 1:
                    continue
    
                original, change_to = row
    
                tags = tree.xpath(f".//name[text()='{original}']")
    
                for tag in tags:
                    tag.text = change_to
    
                    print(f'Changed class {original} to {change_to} in {path}')
    
        with open(path, 'wb') as annotation:
            new_content = lxml.html.tostring(tree)
    
            if new_content.strip():
                annotation.write(new_content)
    
        print(f'Processing on {path} done')
    
    
    if __name__ == '__main__':
        for xml_file in glob.glob('*.xml'):
            if exists(xml_file):
                update_xml(path=xml_file)
    
    
    

    annotation.xml:

    <annotation>
    <folder>./test_xmls</folder>
    <filename>000048_Panorama.jpg</filename>
    <path>./images000048_Panorama.jpg</path>
    <source>
    <database>Unknown</database>
    </source>
    <size>
    <width>4000</width>
    <height>2000</height>
    <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
    <name>AAAA</name>
    <name>BBBB</name>
    <name>CCCC</name>
    <pose>Unspecified</pose>
    <truncated>0</truncated>
    <difficult>0</difficult>
    <bndbox></bndbox></object></annotation>
    

    conversions.csv:

    original,change to
    AAAA,class_A
    BBBB,class_B
    CCCC,class_C
    

    【讨论】:

    • 嗨@Caiolgnm 感谢您的努力。我不愿意制作新的 xml 文件。我已经有更多的多个 xml 文件。我只想根据 csv 更新它们。我试图修改你的代码,但它仍然会抛出错误,就像许多要解包的值一样。你能帮帮我吗?
    • 这里的代码并没有创建新的xml文件,只是更新了原地传入的xml文件。该代码打开 CSV 文件,检查每一行并使用其值更新 xml 文件。这不是你想要的吗?
    • 感谢您的宝贵时间。是的,我想更新相同的 xml。在你的回答中,我猜你只打开一个 xml。我试图通过 glob 打开多个 xml,但并不顺利。我必须更新超过 70k 的 xml 文件。
    • 我已编辑代码以满足您的条件。如果对您有用,请点赞并采纳答案
    • 非常感谢。让我检查一下。
    【解决方案2】:
    import lxml.html  # check https://pypi.org/project/lxml/
    from csv import reader
    import xml.etree.ElementTree as ET
    
    if __name__ == '__main__':
        with open('./table.csv', 'r') as convertions:
            csv_reader = reader(convertions)
            root_path = "./xmls"
    
            xml_list = sorted(os.listdir(root_path))
    
            for xml_file in xml_list:
                xml_path = os.path.join(root_path,xml_file)
                #tree = lxml.html.fromstring(xml_path.read())
                # parse xml file
                tree = ET.parse(xml_path)
    
            for idx, row in enumerate(csv_reader, start=1):
                if idx == 1:
                    continue
    
                original_col, change_to = row
    
                tags = tree.xpath(f".//name[text()='{original_col}']")
    
                for tag in tags:
                    tag.text = change_to
    
                    print(f'Changed class {original_col} to {change_to}')
    
    
                new_content = lxml.html.tostring(tree)
                print(new_content)
    
            if new_content.strip():
                tree.write(new_content)
    

    【讨论】:

      猜你喜欢
      • 2021-05-14
      • 1970-01-01
      • 2021-06-08
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多