Python ElementTree解析XML:表达式变量替换错误的正则方案咨询
问题
使用Python的ElementTree库解析XML文件时,替换metric表达式中的事件名称(如$MyCpu、$MyCpuKernel)为对应val值时出错。当前输出表达式为"73002Kernel / 73002",预期应为"73003 / 73002",想知道能否用正则表达式解决及具体实现方法。
XML片段
<?xml version="1.0" standalone="yes"?> <event_configuration family="21" version="2"> <pqr subtype="abc"> <event val="73002" name="$MyCpu"> </event> <event val="73003" name="$MyCpuKernel"> </event> <metric name="Ratio" expression="$MyCpuKernel / $MyCpu"> </metric> </pqr> </event_configuration>
解析代码
def parse_xml_to_json(self): data = {'metric': []} root = ET.fromstring(self.xml_file) for element in root.findall('.//*'): element_type = element.tag if element_type not in ["pqr", "stu", "vwx"]: continue subtype_name = element.attrib['subtype'] event_map = {} for event in element.findall('.//event'): event_name = event.attrib['name'] val_value = event.attrib['val'] event_map[event_name] = val_value for metric in element.findall('metric'): expression = metric.attrib['expression'] metric_name = metric.attrib['name'] for event_name, val_value in event_map.items(): expression = expression.replace(event_name, val_value) data['metric'].append({ 'Name': metric_name, 'Expression': expression, 'Type': element_type }) return data
错误输出
{ "metric": [ { "Name": "Ratio", "Expression": "73002Kernel / 73002", "Type": "pqr" }, .... .... ] }
解决方案
问题根源
当前用字符串replace方法时,会优先替换短的$MyCpu,导致$MyCpuKernel被截断替换成73002Kernel——因为$MyCpu是$MyCpuKernel的前缀,替换顺序错误引发了部分匹配问题。
方法一:正则表达式精准替换
用正则可以匹配完整的事件变量名,避免部分替换。具体实现:
- 正则规则
r'\$\w+'匹配以$开头、后续由字母/数字/下划线组成的完整变量名 - 通过
re.sub的回调函数,将匹配到的变量名映射为对应的val值
修改后的代码片段:
import re # 保留原代码其他部分,仅替换metric处理块 for metric in element.findall('metric'): expression = metric.attrib['expression'] metric_name = metric.attrib['name'] def replace_var(match): var_name = match.group(0) return event_map.get(var_name, var_name) # 找不到变量时保留原名称 expression = re.sub(r'\$\w+', replace_var, expression) data['metric'].append({ 'Name': metric_name, 'Expression': expression, 'Type': element_type })
方法二:调整替换顺序(无需正则)
如果不想引入正则,可将事件名称按长度从长到短排序,先替换长名称再替换短名称,避免前缀被提前替换:
# 保留原代码其他部分,仅替换metric处理块 for metric in element.findall('metric'): expression = metric.attrib['expression'] metric_name = metric.attrib['name'] # 按事件名称长度倒序排序,优先替换长名称 sorted_events = sorted(event_map.items(), key=lambda x: len(x[0]), reverse=True) for event_name, val_value in sorted_events: expression = expression.replace(event_name, val_value) data['metric'].append({ 'Name': metric_name, 'Expression': expression, 'Type': element_type })
验证结果
两种方法都能得到预期输出:"73003 / 73002"。
内容的提问来源于stack exchange,提问作者NaviB
相关产品推荐
相关产品推荐

