遍历XML目录合并数据至Pandas DataFrame后数据为空的问题排查
问题描述
需要解析一个嵌套XML文件目录,并将结果合并到单个Pandas DataFrame中。单个文件解析已成功,但遍历目录合并时,最终DataFrame始终为空。
示例XML文件
<annotation> <folder>VOC2007</folder> <filename>361_0_00020.jpg</filename> <size> <width>800</width> <height>800</height> <depth>3</depth> </size> <segmented>0</segmented> <object> <name>361</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>338</xmin> <ymin>361</ymin> <xmax>430</xmax> <ymax>430</ymax> </bndbox> </object> <object> <name>361</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>24</xmin> <ymin>16</ymin> <xmax>240</xmax> <ymax>156</ymax> </bndbox> </object> </annotation>
单个文件解析代码(可正常运行)
import pandas as pd import xml.etree.ElementTree as et tree= et.parse("/content/drive/MyDrive/361_0_00020.xml") root=tree.getroot() filename = root.find('filename').text obj= root.find('object') bnb = obj.find('bndbox') xmin = bnb.find('xmin').text ymin = bnb.find('ymin').text xmax = bnb.find('xmax').text ymax = bnb.find('ymax').text list_1 = [filename, xmin, ymin, xmax, ymax] df_cols= ['filename','xmin', 'ymin', 'xmax', 'ymax'] df= pd.DataFrame([list_1], columns=df_cols) df
遍历目录的代码(执行后DataFrame为空)
import os import pandas as pd import xml.etree.ElementTree as et df_cols= ['filename','xmin', 'ymin', 'xmax', 'ymax'] df= pd.DataFrame([], columns=df_cols) path= '/content/drive/MyDrive/Annotations' for filename in os.listdir(path): if not filename.endswith('.xml'): continue fullname = os.path.join(path, filename) tree = et.parse(fullname) root=tree.getroot() for child in root: fnm = root.find('filename').text obj= root.find('object') bnb = obj.find('bndbox') xmin = bnb.find('xmin').text ymin = bnb.find('ymin').text xmax = bnb.find('xmax').text ymax = bnb.find('ymax').text list_2 = [[fnm, xmin, ymin, xmax, ymax]] df.append(pd.DataFrame(list_2))
问题原因与解决方案
1. df.append() 不会修改原DataFrame
Pandas的append()方法返回新的DataFrame,不会直接修改原对象。你只调用了df.append(...)但没有把返回值赋值给df,所以原df始终是空的。
2. 遍历逻辑错误
- 内层
for child in root:完全没必要,这个循环会遍历annotation下的所有子节点(folder、filename、size等),导致同一个XML里的对象被重复处理多次。 root.find('object')只会找到第一个<object>节点,XML里的多个对象会被忽略。
修正后的代码
import os import pandas as pd import xml.etree.ElementTree as et df_cols = ['filename','xmin', 'ymin', 'xmax', 'ymax'] # 用列表存储所有数据,最后一次性生成DataFrame,效率更高 data_list = [] path = '/content/drive/MyDrive/Annotations' for filename in os.listdir(path): if not filename.endswith('.xml'): continue fullname = os.path.join(path, filename) tree = et.parse(fullname) root = tree.getroot() fnm = root.find('filename').text # 遍历所有<object>节点 for obj in root.findall('object'): bnb = obj.find('bndbox') xmin = bnb.find('xmin').text ymin = bnb.find('ymin').text xmax = bnb.find('xmax').text ymax = bnb.find('ymax').text data_list.append([fnm, xmin, ymin, xmax, ymax]) # 最后一次性生成DataFrame df = pd.DataFrame(data_list, columns=df_cols)
额外优化说明
- 避免在循环中反复调用
df.append(),因为每次append都会创建新的DataFrame,效率极低。用列表收集所有数据,最后统一生成DataFrame是更高效的做法。 - 使用
root.findall('object')获取所有对象节点,确保XML里的多个object都被处理。
内容的提问来源于stack exchange,提问作者Jonathan Grenner
相关产品推荐
相关产品推荐

