Python3使用lxml解析XML转嵌套字典异常,寻求问题排查
解决lxml解析XML转嵌套字典列表的异常问题
我来帮你捋捋代码里的问题,你现在遇到的异常结果大概率是这几个逻辑漏洞导致的:
问题分析
列表引用共享问题:你每次遇到
TowerName时调用roomList.clear(),但之后把roomList直接赋值给self.bigMeetingRoom[indexTower]——这会导致所有塔楼对应的列表都是同一个内存引用,后续添加新房间时会覆盖之前的所有数据,或者出现所有塔楼列表内容一致的情况。逻辑顺序混乱:你在获取
roomMailId后立刻把房间字典加入列表,紧接着判断roomSize并赋值,但这个判断时机不对:如果XML里BigMeetingRooms/SmallMeetingRooms节点出现在房间信息之后,roomSize会未定义,引发UnboundLocalError;而且你完全没处理小会议室的存储逻辑。未处理空文本与变量初始化:如果XML节点的
text是None(比如空节点),直接赋值会导致后续字典出现None键/值;同时如果节点顺序异常,可能会使用未初始化的变量。
修正后的代码
from lxml import etree # 先确保两个字典已初始化 self.bigMeetingRoom = {} self.smallMeetingRoom = {} tree = etree.parse(self.meetingXmlFile) root = tree.getroot() current_tower = None current_room_size = None current_room_list = [] for child in root.iter(): if child.tag == "TowerName": # 遇到新塔楼时,先把上一个塔楼的房间列表存入对应字典 if current_tower and current_room_size: if current_room_size == "bigMeetingRoom": self.bigMeetingRoom[current_tower] = current_room_list.copy() elif current_room_size == "smallMeetingRoom": self.smallMeetingRoom[current_tower] = current_room_list.copy() # 初始化新塔楼的变量:创建新列表,避免引用共享 current_tower = child.text.strip() if child.text else "" current_room_list = [] elif child.tag == "BigMeetingRooms": current_room_size = "bigMeetingRoom" elif child.tag == "SmallMeetingRooms": current_room_size = "smallMeetingRoom" elif child.tag == "MeetingRoomName": room_name = child.text.strip() if child.text else "" elif child.tag == "MeetingRoomMailId": room_mail_id = child.text.strip() if child.text else "" # 确认有有效名称和房间类型后,再加入列表 if room_name and current_room_size: current_room_list.append({room_name: room_mail_id}) # 循环结束后,别忘了存入最后一个塔楼的房间数据 if current_tower and current_room_size: if current_room_size == "bigMeetingRoom": self.bigMeetingRoom[current_tower] = current_room_list elif current_room_size == "smallMeetingRoom": self.smallMeetingRoom[current_tower] = current_room_list print(self.bigMeetingRoom)
优化建议:按XML层级遍历
如果你的XML是层级结构(比如<Tower>下包含<TowerName>、<BigMeetingRooms>,后者再包含<MeetingRoom>节点),建议用层级遍历代替全局iter(),逻辑更清晰,不容易出错:
from lxml import etree self.bigMeetingRoom = {} self.smallMeetingRoom = {} tree = etree.parse(self.meetingXmlFile) root = tree.getroot() # 假设XML结构是 <Root><Tower><TowerName>...</TowerName><BigMeetingRooms><MeetingRoom>...</MeetingRoom></BigMeetingRooms></Tower></Root> for tower in root.findall("Tower"): tower_name = tower.findtext("TowerName") if not tower_name: continue # 处理大会议室 big_rooms_section = tower.find("BigMeetingRooms") if big_rooms_section is not None: big_room_list = [] for room in big_rooms_section.findall("MeetingRoom"): room_name = room.findtext("MeetingRoomName") room_mail = room.findtext("MeetingRoomMailId") if room_name and room_mail: big_room_list.append({room_name.strip(): room_mail.strip()}) self.bigMeetingRoom[tower_name.strip()] = big_room_list # 处理小会议室 small_rooms_section = tower.find("SmallMeetingRooms") if small_rooms_section is not None: small_room_list = [] for room in small_rooms_section.findall("MeetingRoom"): room_name = room.findtext("MeetingRoomName") room_mail = room.findtext("MeetingRoomMailId") if room_name and room_mail: small_room_list.append({room_name.strip(): room_mail.strip()}) self.smallMeetingRoom[tower_name.strip()] = small_room_list print(self.bigMeetingRoom)
这种方式完全贴合XML的层级结构,避免了全局遍历带来的逻辑混乱,也更容易维护。
内容的提问来源于stack exchange,提问作者avinashse
相关产品推荐
相关产品推荐

