ElementTree解析含孤立&字符日志报错,求预处理或排查方案
问题分析与解决方案
你的问题根源很明确:XML语法要求所有&字符必须转义为&,单独出现的&属于非法token,这就是触发xml.etree.ElementTree.ParseError的原因。当&后面跟了amp;时,它已经是合法的转义字符,所以解析没问题。
你完全可以在解析前对每一行日志做预处理,修复未转义的&字符,不需要排查其他故障。下面是具体的解决步骤和优化后的代码:
核心修复:替换未转义的&
我们需要用正则表达式精准匹配没有跟随amp;的&字符,避免把已经合法的&再次转义成&。可以用负向预查的正则:r'&(?!amp;)',意思是匹配后面不是amp;的&。
优化后的完整代码
import xml.etree.ElementTree as ET import os import re # 用原始字符串避免路径转义问题 path = r"C:\Users\SuperUser\Desktop\audit\audit\saved\audit" # 用with语句自动管理文件,避免忘记关闭 with open("logins.xml", "w", encoding="UTF-8") as xmlfile: # 先写入根节点开头(原来的代码每行都写xml声明和root,会生成无效的XML) xmlfile.write('<?xml version="1.0" encoding="UTF-8"?>\n<root>\n') for filename in os.listdir(path): file_path = os.path.join(path, filename) # 用os.path.join更安全的拼接路径 with open(file_path, encoding="UTF-8") as myfile: for line in myfile: line = line.strip() if not line: continue # 预处理:修复未转义的&字符 cleaned_line = re.sub(r'&(?!amp;)', r'&', line) try: xmlVal = ET.fromstring(cleaned_line) finder = "UserAuthenticated/Action" action_elem = xmlVal.find(finder) if action_elem is not None and action_elem.text == 'Login': username_elem = xmlVal.find("UserAuthenticated/LocalUsername") timestamp_elem = xmlVal.find("TimeStamp") # 避免元素不存在导致的AttributeError if username_elem is not None and timestamp_elem is not None: username = username_elem.text timestamp = timestamp_elem.text # 用f-string更简洁,同时避免手动拼接XML的转义问题 xml_entry = f' <entry>\n <Username>{username}</Username>\n <Timestamp>{timestamp}</Timestamp>\n </entry>\n' xmlfile.write(xml_entry) print(f"Writing entry for user {username} at {timestamp} to logins.xml") except ET.ParseError as e: print(f"Failed to parse line in {filename}: {line}") print(f"Error: {e}") # 写入根节点结尾 xmlfile.write('</root>')
额外优化说明
- 路径处理:用
os.path.join拼接路径,避免手动用反斜杠导致的跨平台问题和转义错误;路径字符串用原始字符串r""。 - 文件管理:用
with语句自动关闭文件,比手动调用close()更安全。 - XML结构修复:原来的代码每行都写入完整的XML声明和
<root>,会生成多个根节点的无效XML。现在改为只写一次根节点,每行写入<entry>子节点,生成合法的XML结构。 - 异常处理:添加
try-except捕获解析错误,方便定位有问题的行,不会因为某一行错误导致整个程序中断。 - 空行跳过:跳过空行,避免解析空字符串报错。
- 元素存在检查:增加对
username_elem和timestamp_elem的存在检查,避免元素不存在时访问.text抛出AttributeError。
其他注意事项
如果日志里还存在其他XML非法字符(比如未转义的<、>、"、'),你可能需要扩展预处理逻辑,比如用xml.sax.saxutils.escape函数,但要注意这个函数会把所有&都转义,所以要先处理已经存在的&,或者先调用escape再把&amp;改回&。
内容的提问来源于stack exchange,提问作者Lycan
相关产品推荐
相关产品推荐

