ElementTree解析特定XML仅获根元素,报KeyError: 'size'问题求助
问题:解析海康威视摄像头OSD XML配置时触发KeyError
问题场景
编写Python脚本获取摄像头OSD配置并提取Inventory ID,已实现XML下载与解析逻辑,但解析第二个配置文件时抛出KeyError: 'size'异常。
原代码
import xml.etree.ElementTree as ET first_config = """ <VideoOverlay xmlns="http://www.hikvision.com/ver20/XMLSchema" version="2.0"> <normalizedScreenSize> <normalizedScreenWidth>704</normalizedScreenWidth> <normalizedScreenHeight>576</normalizedScreenHeight> </normalizedScreenSize> <attribute> <transparent>false</transparent> <flashing>false</flashing> </attribute> <TextOverlayList size="4"> <TextOverlay> <id>1</id> <enabled>true</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText>Inv: 1234513454321</displayText> <directAngle/> </TextOverlay> </TextOverlayList> <DateTimeOverlay> <enabled>true</enabled> <positionX>552</positionX> <positionY>560</positionY> <dateStyle>DD-MM-YYYY</dateStyle> <timeStyle>24hour</timeStyle> <displayWeek>false</displayWeek> </DateTimeOverlay> <channelNameOverlay> <enabled>true</enabled> <positionX>553</positionX> <positionY>48</positionY> </channelNameOverlay> <fontSize>48*48</fontSize> <frontColorMode>auto</frontColorMode> <frontColor>000000</frontColor> <alignment>customize</alignment> <boundary>1</boundary> </VideoOverlay> """ second_config = """ <VideoOverlay xmlns="http://www.hikvision.com/ver20/XMLSchema" version="2.0"> <normalizedScreenSize> <normalizedScreenWidth>704</normalizedScreenWidth> <normalizedScreenHeight>576</normalizedScreenHeight> </normalizedScreenSize> <attribute> <transparent>false</transparent> <flashing>false</flashing> </attribute> <fontSize>48*48</fontSize> <TextOverlayList size="8"> <TextOverlay> <id>1</id> <enabled>true</enabled> <positionX>3</positionX> <positionY>48</positionY> <displayText>Inv: 100000000</displayText> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>2</id> <enabled>true</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText>GEO:0000000000</displayText> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>3</id> <enabled>true</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText>Serial:000000000</displayText> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>4</id> <enabled>true</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText>MODEL:0000000000000</displayText> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>5</id> <enabled>false</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText/> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>6</id> <enabled>false</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText/> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>7</id> <enabled>false</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText/> <isPersistentText>true</isPersistentText> </TextOverlay> <TextOverlay> <id>8</id> <enabled>false</enabled> <positionX>0</positionX> <positionY>576</positionY> <displayText/> <isPersistentText>true</isPersistentText> </TextOverlay> </TextOverlayList> <DateTimeOverlay> <enabled>true</enabled> <positionX>0</positionX> <positionY>576</positionY> <dateStyle>DD-MM-YYYY</dateStyle> <timeStyle>24hour</timeStyle> <displayWeek>false</displayWeek> </DateTimeOverlay> <channelNameOverlay xmlns="http://www.hikvision.com/ver20/XMLSchema" version="2.0"> <enabled>true</enabled> <positionX>581</positionX> <positionY>48</positionY> </channelNameOverlay> <frontColorMode>auto</frontColorMode> <frontColor>000000</frontColor> <alignment>customize</alignment> <boundary>1</boundary> <upDownboundary>0</upDownboundary> <leftRightboundary>0</leftRightboundary> </VideoOverlay> """ xml_string = first_config root = ET.fromstring(xml_string) print(root.tag) osd_list_size = root[2].attrib['size'] print(osd_list_size) #size of the list of OSD lines for child in root[2]: print(child[4].text) xml_string = second_config root_b = ET.fromstring(xml_string) print(root_b.tag) osd_list_size = root_b[2].attrib['size'] print(osd_list_size) #size of the list of OSD lines for child in root_b[2]: print(child[4].text)
报错信息
Traceback (most recent call last): File "C:\Users\S26-tech-Dmt\PycharmProjects\pythonProject1\Test.py", line 159, in <module> osd_list_size = root_b[2].attrib['size'] ~~~~~~~~~~~~~~~~^^^^^^^^ KeyError: 'size'
问题原因
- 元素顺序不一致:第一个配置中
TextOverlayList是根元素的第3个子元素(索引2),但第二个配置里,根元素的第3个子元素是<fontSize>,TextOverlayList在其后方。直接通过索引访问子元素的方式依赖固定顺序,兼容性极差。 - 忽略XML命名空间:XML根元素带有命名空间
xmlns="http://www.hikvision.com/ver20/XMLSchema",默认情况下ElementTree查找元素时需要指定命名空间,否则可能无法正确匹配标签。
修复方案
放弃索引定位,改用命名空间+标签名的方式查找目标元素,确保无论元素顺序如何都能正确定位。同时优化Inventory ID的提取逻辑,直接过滤包含Inv:的文本。
修改后的代码
import xml.etree.ElementTree as ET # 定义XML命名空间 NS = {'hik': 'http://www.hikvision.com/ver20/XMLSchema'} def extract_inventory_id(xml_content): root = ET.fromstring(xml_content) # 通过命名空间查找TextOverlayList text_overlay_list = root.find('hik:TextOverlayList', NS) if not text_overlay_list: print("未找到TextOverlayList元素") return # 获取size属性(可选,可根据需求保留) osd_list_size = text_overlay_list.attrib.get('size', '未知') print(f"OSD列表大小: {osd_list_size}") # 遍历所有TextOverlay元素 for overlay in text_overlay_list.findall('hik:TextOverlay', NS): display_text = overlay.find('hik:displayText', NS).text if display_text and 'Inv:' in display_text: # 提取Inventory ID inv_id = display_text.split('Inv:')[-1].strip() print(f"Inventory ID: {inv_id}") # 测试第一个配置 print("=== 解析第一个配置 ===") extract_inventory_id(first_config) # 测试第二个配置 print("\n=== 解析第二个配置 ===") extract_inventory_id(second_config)
代码说明
- 定义命名空间字典
NS,用于正确匹配带命名空间的XML标签。 - 使用
find()和findall()方法结合命名空间查找元素,不依赖元素顺序。 - 通过
attrib.get()获取属性,避免KeyError(若属性不存在则返回默认值)。 - 直接过滤包含
Inv:的文本,精准提取Inventory ID,无需依赖固定索引访问子元素。
内容的提问来源于stack exchange,提问作者Tano Dz
相关产品推荐
相关产品推荐

