在使用Python处理XML数据时,经常会遇到XML中包含非法字符导致解析失败的问题,这类非法字符通常包括ASCII控制字符、未正确转义的特殊符号等,会让标准解析库抛出解析异常。

常见的XML非法字符类型
XML规范中明确规定了合法的字符范围,超出范围的字符都属于非法字符,常见的有以下几种:
- ASCII控制字符:比如<、>、&等符号未做转义,或者0x00到0x1F之间的控制字符(除了换行、回车、制表符)
- 未配对的标签符号:比如只有开始标签没有结束标签,或者属性值没有闭合引号
- 非法实体引用:引用了XML中未定义的实体名称
方案一:预处理清洗非法字符
最常用的解决方式是在解析前对XML字符串做预处理,把非法字符过滤或者替换掉,再交给标准解析库处理。可以通过正则表达式匹配非法字符并移除。
import re
import xml.etree.ElementTree as ET
def clean_xml_illegal_chars(xml_str):
# 匹配XML规范外的控制字符,保留换行、回车、制表符
pattern = re.compile(r'[x00-x08x0bx0cx0e-x1fx7f]')
# 替换非法控制字符为空
cleaned_str = pattern.sub('', xml_str)
# 处理未转义的&符号,把单独的&替换为&,注意避免替换已经转义的&
# 这里简单处理,实际场景可以根据需求调整
cleaned_str = re.sub(r'&(?!amp;|lt;|gt;|quot;|apos;)', '&', cleaned_str)
return cleaned_str
# 示例含非法字符的XML
raw_xml = '''<?xml version="1.0" encoding="utf-8"?>
- 正常内容x01非法控制字符
- 未转义的&符号测试
'''
# 清洗后解析
cleaned_xml = clean_xml_illegal_chars(raw_xml)
try:
tree = ET.fromstring(cleaned_xml)
for item in tree.findall('item'):
print(item.text)
except ET.ParseError as e:
print(f"解析失败: {e}")
方案二:自定义XML解析器适配
如果需要更灵活的处理,可以自定义XML解析器,在解析过程中遇到非法字符时做自定义处理,而不是直接抛出异常。可以基于xml.sax模块实现自定义处理器。
import xml.sax
from xml.sax.handler import ContentHandler
class IllegalCharHandler(ContentHandler):
def __init__(self):
self.result = []
self.current_tag = None
def startElement(self, name, attrs):
self.current_tag = name
self.result.append(f"<{name}>")
def characters(self, content):
# 处理字符内容中的非法字符
cleaned_content = ''.join(c for c in content if ord(c) >= 0x20 or c in 'nrt')
if self.current_tag:
self.result.append(cleaned_content)
def endElement(self, name):
self.result.append(f"</{name}>")
self.current_tag = None
# 示例XML
test_xml = '''<?xml version="1.0" encoding="utf-8"?>
张三x02
20
'''
handler = IllegalCharHandler()
parser = xml.sax.make_parser()
parser.setContentHandler(handler)
# 需要把XML字符串转为字节流传入
try:
parser.feed(test_xml.encode('utf-8'))
parser.close()
print(''.join(handler.result))
except Exception as e:
print(f"处理异常: {e}")
两种方案的选择建议
如果是批量的XML文件处理,优先选择预处理清洗的方式,效率更高且逻辑简单;如果是需要保留原始XML结构,仅处理个别非法字符的场景,自定义解析器会更灵活。实际使用时可以根据数据的特点和解析需求选择合适的方案,必要时可以结合两种方式共同处理。
注意事项
预处理替换字符时需要注意不要误删合法内容,尤其是处理特殊符号转义时,要避免破坏已经正确转义的实体。如果XML中包含CDATA段,需要额外处理CDATA段内的内容,避免把CDATA中的合法特殊符号误判为非法字符。
另外,处理完成后建议对清洗后的XML做一次合法性校验,确保处理后的XML可以被标准库正常解析,避免后续数据处理出现其他异常。
PythonXML解析非法字符处理re模块ElementTree修改时间:2026-06-13 15:15:30