
在使用 lxml 解析含 \n 的 XML 属性时,Windows 系统默认将换行符规范化为空格,导致原始换行丢失;本文提供手动预处理( 编码)与验证方法,确保跨平台一致保留换行语义。
在使用 lxml 解析含 `\n` 的 xml 属性时,windows 系统默认将换行符规范化为空格,导致原始换行丢失;本文提供手动预处理(` ` 编码)与验证方法,确保跨平台一致保留换行语义。
XML 规范(XML 1.0 §2.11)明确规定:属性值中的空白字符(包括 \n、\r、\t)在解析时需执行规范化(Normalization)——即所有换行符(#x0A)、回车符(#x0D)和制表符(#x09)统一替换为单个空格。这是标准行为,而非 lxml 或 Windows 的“bug”。因此,在 Windows 上观察到
但若业务逻辑依赖原始换行(如多行提示文本、格式化配置等),可通过以下方式绕过规范化:
通过 handsfree-windows CLI控制 Windows 本机应用 (UIA) 和浏览器 (Playwright) 的引导技能,用于自动化或测试桌面应用。
✅ 推荐方案:预编码为字符引用
在调用 etree.fromstring() 前,将原始字符串中的 \n 替换为标准 XML 字符引用
(LF 的十进制实体)。lxml 会正确解码该实体为 \n,且不触发规范化:
from lxml import etree
# 原始含换行的 XML 字符串(来自文件/网络等)
xml_str = '<root attr1="line1\nline2"></root>'
# 手动预处理:将 \n →
xml_fixed = xml_str.replace('\n', '
')
# 安全解析
root = etree.fromstring(xml_fixed)
value = root.get('attr1')
print(repr(value)) # 'line1\nline2'
print(value) # line1
# line2
⚠️ 注意事项:
- 此方法仅适用于你可控的 XML 字符串输入源(如动态生成、读取本地文件后处理);若 XML 由第三方提供且已按规范编码(如含 或 '),则无需额外处理;
- 不要对整个 XML 文档盲目 .replace('\n', ' '),仅针对属性值中的换行(或使用正则精准匹配 attr="[^"]*\n[^"]*");
- 避免使用 xml.sax 或 minidom 替代方案——它们同样遵循 XML 规范,无法禁用规范化;
- 若需序列化回 XML 并保持可读性,etree.tostring(..., encoding='unicode') 会自动将 \n 输出为 ,符合标准且可被任何 XML 解析器正确还原。
? 总结:XML 属性换行丢失是规范强制行为,非实现缺陷。通过输入前将 \n 显式转义为 ,即可在 lxml 中完整保留换行语义,实现跨平台一致的行为。










