Python ElementTree与bs4解析XML报格式错误问题排查
两个完全独立实现的XML解析库在相同行列位置抛出完全一致的格式校验错误,可直接排除解析代码逻辑/写法问题,错误100%来自待解析的XML备份文件本身不符合W3C XML格式规范。
错误根因定位
ParseError: not well-formed (invalid token): line 3, column 13明确指向文件第3行第13个字符位置存在XML规范不允许的非法内容,这类短信备份文件的常见触发原因按出现概率排序:
- 未转义特殊字符:XML要求
<、>、&三个字符必须转义为对应实体(</>/&),绝大多数短信备份工具导出时不会对短信正文做转义处理,正文里出现&、<3类表情、特殊符号时就会触发错误 - 属性值未加引号:XML强制要求所有标签属性值必须用单/双引号包裹,如果第3行标签属性格式为
<sms address=10086 date=1620000000>而非标准的<sms address="10086" date="1620000000">,属性值起始位置就会被判定为非法token - 编码不匹配:XML头部声明的编码和文件实际存储编码不一致(比如声明为UTF-8但实际是GBK编码保存),中文字符会被识别为非法字节序列
- 非法控制字符:导出过程中混入了ASCII 0-31范围内的不可见控制字符(制表符、换行、回车除外),这类字符不被XML规范允许直接出现
排查&修复方案
- 先用纯文本编辑器(VS Code/Notepad++均可)打开XML文件,直接跳转到第3行第13列位置,肉眼即可确认具体是上述哪类问题。
- 不建议手动修改原备份文件,通过代码容错/预处理即可正常解析:
- bs4容错解析方案(最简单,无需手动处理非法字符):
from bs4 import BeautifulSoup with open("sms_backup.xml", "r", encoding="utf-8", errors="ignore") as f: # 选用带容错能力的html.parser解析器,自动兼容不规范XML soup = BeautifulSoup(f.read(), "html.parser") # 后续正常提取标签即可,示例: all_sms = soup.find_all("sms") for sms in all_sms: print(sms.get("address"), sms.get("body")) - ElementTree预处理解析方案:
import xml.etree.ElementTree as ET import re with open("sms_backup.xml", "r", encoding="utf-8", errors="ignore") as f: raw_content = f.read() # 替换未转义的&符号,避开已合法转义的实体 fixed_content = re.sub(r'&(?!(lt|gt|amp|quot|apos);)', '&', raw_content) # 移除非法不可见控制字符 fixed_content = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f]', '', fixed_content) root = ET.fromstring(fixed_content) # 后续正常遍历节点即可
- bs4容错解析方案(最简单,无需手动处理非法字符):
验证说明
添加上述容错/预处理逻辑后如果解析正常,即可完全确认问题来自备份文件本身的格式缺陷,和解析代码写法无关——非专业导出工具生成的XML备份不做特殊字符转义是这类问题的最高发诱因。
内容的提问来源于stack exchange,提问作者user3087182
相关产品推荐
相关产品推荐

