Python解析含动态数据的多XML节点类XML格式应用日志方案咨询
类XML格式日志解析方案
一、分组解析方案
单独解析每个group是最优实现方案,既可以保留trace行携带的业务元数据,也不会出现节点归属混乱的问题,处理数百个group时内存占用和解析效率都优于整文件统一解析,具体实现逻辑如下:
- 按行拆分日志文件,识别所有
[trace-开头的行作为分组边界,同步解析trace行内的TransactionID、TransactionName、User等元数据存为键值对 - 取两个相邻trace行之间的内容作为单个group的XML片段,删除片段内的
<?xml声明后,外层包裹<group>根节点即可单独生成解析树 - 将每个group的解析结果和对应的trace元数据绑定存储,不会出现节点归属混淆的问题
二、动态存储srvdata方案
针对srvdata下字段、数量不固定的场景,直接转为Python字典存储即可,无需预定义结构:
- 递归遍历
srvdata节点的所有子节点,以节点标签为字典key,节点文本/属性为value,遇到同标签多节点时自动转为列表存储 - 单个group的存储结构参考:
group_item = { "trace_info": { "TransactionID": "6010", "TransactionName": "CPM.ExecuteDiscernScript", "User": "MEPPS" }, "RequestMeta": {}, # 对应RequestMeta下srvdata的转换结果 "Request": {}, # 对应Request下srvdata的转换结果 "ReplyMeta": {}, # 对应ReplyMeta下srvdata的转换结果 "Reply": {} # 对应Reply下srvdata的转换结果 }
- 所有group存为列表即可满足后续查询、导出需求。
三、优化后代码示例
import xml.etree.ElementTree as ET import re # 递归将XML节点转为字典 def element_to_dict(element): result = {} # 存储节点属性 if element.attrib: result.update(element.attrib) # 处理子节点 for child in element: child_dict = element_to_dict(child) if child.tag in result: # 同标签多节点转为列表存储 if not isinstance(result[child.tag], list): result[child.tag] = [result[child.tag]] result[child.tag].append(child_dict) else: result[child.tag] = child_dict # 存储节点文本 if element.text and element.text.strip(): if result: result['#text'] = element.text.strip() else: result = element.text.strip() return result all_groups = [] with open('C:/code/mra/requestreply.txt', 'r', encoding='utf-8') as f: lines = f.readlines() # 定位所有trace行的索引 trace_positions = [] for idx, line in enumerate(lines): if line.startswith('[trace-'): trace_positions.append(idx) # 补充文件末尾作为最后一个group的边界 trace_positions.append(len(lines)) # 逐个解析group for i in range(len(trace_positions)-1): start_idx = trace_positions[i] end_idx = trace_positions[i+1] # 解析trace行元数据 trace_info = dict(re.findall(r'(\w+)=(\S+)', lines[start_idx])) # 提取当前group的XML内容 group_xml = ''.join(lines[start_idx+1: end_idx]) # 移除XML声明 group_xml = re.sub(r'<\?xml.*?\?>', '', group_xml) # 包裹根节点 group_xml = f'<group>{group_xml}</group>' # 解析XML root = ET.fromstring(group_xml) # 提取四个节点的srvdata group_item = {"trace_info": trace_info} for node_name in ["RequestMeta", "Request", "ReplyMeta", "Reply"]: node = root.find(node_name) srvdata = node.find('.//srvdata') if node is not None else None group_item[node_name] = element_to_dict(srvdata) if srvdata is not None else {} all_groups.append(group_item)
四、简易网页生成方案
如需输出表格样式的网页,可使用Jinja2模板渲染实现:
- 编写基础HTML模板,表头按需配置需要展示的字段
- 将
all_groups列表传入模板,循环渲染每行数据,针对srvdata的动态字段,可遍历字典键值对动态生成单元格内容。
内容的提问来源于stack exchange,提问作者Yitzhak
相关产品推荐
相关产品推荐

