如何匹配XML1指定格式的Equal元素并打印XML2中对应元素行号
问题描述
我有如下格式的XML1,其中<Equal>元素包含三种合法格式:两个<Data>子元素、两个<Integer>子元素、先<Integer>后<Data>子元素:
<Operator> <Equal> <Data>OPERATING_MODE</Data> <Data>2</Data> </Equal> <Equal> <Integer>Remote_Request</Integer> <Data>2</Data> </Equal> <Equal> <Integer>Real_area</Integer> <Integer>2</Integer> </Equal> </Operator>
我原本用以下代码在小型XML的System1中查找元素并打印Label:
doc = etree.parse('C:/Python/Sample.xml') doc2 = etree.parse('C:/Python/Project.xml') values = [e.xpath('.//*[2]')[0].text for e in doc.xpath('.//Equal')] for service in doc2.xpath('.//System1//Data[Label]'): value = service.xpath('.//Equal//*[2]/text()')[0] if value in values: # 获取对应Label的值 print(service.xpath('.//Label/text()')[0])
但我的XML2有10万+行,结构复杂,示例如下:
<File> <System1> <Messages> <Setting_Report> <Data> <Label>A1</Label> <Bit_count>1</Bit_count> <Value> <Equal> <Data>Data</Data> <Data>2</Data> </Equal> </Value> </Data> <Data> <Label>A2</Label> <Bit_count>1</Bit_count> <Value> <Value> <Equal> <Data>Data</Data> <Data>2</Data> </Equal> </Value> </Value> </Data> <Data> <Label>A3</Label> <Bit_count>1</Bit_count> <Value> <Data>Data</Data> </Value> </Data> <Data> <Label>A4</Label> <Bit_count>1</Bit_count> </Data> <Data> <Label>A5</Label> <Bit_count>1</Bit_count> </Data> <Data> <Label>A35</Label> <Bit_count>1</Bit_count> <Value> <Value> <Equal> <Data>Data</Data> <Data>2</Data> </Equal> </Value> </Value> </Data> </Setting_Report> <Status_Report> <Data> <Label>Real_area_1</Label> <Bit_count>8</Bit_count> <Value> <Equal> <Data>Yes</Data> <Data>2</Data> </Equal> </Value> </Data> <Data> <Label>Real_area_2</Label> <Bit_count>8</Bit_count> <Value> <Value_on_condition> <Case> <Value> <Integer>1</Integer> </Value> <Condition> <Equal> <Integer>No</Integer> <Integer>2</Integer> </Equal> </Condition> </Case> <Case> <Value> <Data>Order</Data> </Value> <Condition/> </Case> </Value_on_condition> </Value> </Data> </Status_Report> </Messages> </System1> <System2> <Basic> <Data> <!--A1--> <Label>Area_1</Label> <Direction>Out</Direction> <Bit_count>1</Bit_count> <Value> <Default_value_if_undefined> <Value> <!----> <Value_on_boolean> <And> <Equal> <Data>area_id</Data> <Data>2</Data> </Equal> <Data>Redundant</Data> </And> <Value_if_true> <Integer>1</Integer> </Value_if_true> <Value_if_false> <Integer>0</Integer> </Value_if_false> </Value_on_boolean> </Value> <Default_value> <Integer>0</Integer> </Default_value> </Default_value_if_undefined> </Value> </Data> </Basic> </System2> </File>
运行上述代码后仅打印前两个Label就抛出错误:
A1 A2 Traceback (most recent call last): File "C:\Syntax\Syntax.py", line 11, in <module> value = service.xpath('.//Equal//*[2]/text()')[0] IndexError: list index out of range
现在我不需要打印Label,而是要在XML2中找到所有符合XML1三种格式的<Equal>元素,并打印这些元素所在的行号(示例XML2中目标行号为10,21,48,61,77,108,137,171)。
解决方案
核心思路
- 原错误原因:部分
<Data>节点下无<Equal>元素,或<Equal>子元素数量不足2个,直接取索引[0]触发越界。 - 大XML处理:用
lxml的iterparse迭代解析,避免一次性加载全量数据,降低内存占用。 - 格式校验:严格检查
<Equal>是否包含恰好2个子元素,且子元素标签符合三种合法组合。 - 行号获取:利用
lxml元素的sourceline属性直接读取元素在原文件中的起始行号。
代码实现
from lxml import etree # 校验Equal元素是否符合合法格式 def is_valid_equal(equal_elem): children = list(equal_elem) # 必须有且仅有2个子元素 if len(children) != 2: return False tag1, tag2 = children[0].tag, children[1].tag # 匹配三种合法组合 return (tag1 == 'Data' and tag2 == 'Data') or \ (tag1 == 'Integer' and tag2 == 'Integer') or \ (tag1 == 'Integer' and tag2 == 'Data') # 迭代解析大XML文件 for event, elem in etree.iterparse('C:/Python/Project.xml', events=('start',)): if elem.tag == 'Equal': if is_valid_equal(elem): print(elem.sourceline) # 清理已处理元素,释放内存 elem.clear() while elem.getprevious() is not None: del elem.getparent()[0]
代码说明
- 迭代解析:
iterparse逐行读取XML,仅在遇到<Equal>时处理,适合超大型文件,避免内存溢出。 - 格式校验:
is_valid_equal函数确保<Equal>的子元素数量和标签组合完全符合要求。 - 行号获取:
elem.sourceline直接返回<Equal>元素在原XML中的起始行号,满足需求。 - 内存优化:处理完每个
<Equal>后清理元素并删除父节点中的旧元素,防止内存占用过高。
注意事项
- 确保XML文件无语法错误,否则
iterparse会抛出解析异常。 - 若XML含命名空间,需用
etree.QName(elem.tag).localname获取不带命名空间的标签名进行判断。
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

