Boost.PropertyTree的write_xml()默认不格式化XML,输出无换行缩进;需显式传xml_writer_settings控制格式,注意UTF-8编码与BOM问题,且不支持大文件和复杂XML特性。

为什么 write_xml() 生成的 XML 没有换行和缩进?
默认不格式化,这是 Boost.PropertyTree 最常被吐槽的一点。它把 XML 当作纯数据序列化工具用,不是为了人眼可读。
实操上必须显式传入 xml_writer_settings,否则输出是单行、无缩进、属性顺序随机的紧凑格式:
ptree pt; pt.put("root.child", "value"); write_xml("out.xml", pt); // → <root><child>value</child></root>
- 加缩进:传入
xml_writer_settings<std::string>(" ", 1)(4空格 + 换行) - 避免中文乱码:确保
ptree中字符串是 UTF-8 编码,且写入时用std::locale::global(std::locale(""))或显式指定 UTF-8 facet(Windows 下尤其关键) - 注意:
write_xml()默认会写<?xml version="1.0" encoding="utf-8"?>声明,但不会校验内容是否真为 UTF-8
read_xml() 报错 xml_parser_error 怎么定位?
这个错误信息极简,只告诉你“解析失败”,不告诉你哪一行、什么标签出问题。常见于 XML 格式不规范或编码不匹配。
调试建议优先做三件事:
立即学习“C++免费学习笔记(深入)”;
- 用外部工具(如
xmllint --noout file.xml)先验证 XML 合法性;PropertyTree 不支持 DTD、命名空间、CDATA 块,遇到就崩 - 检查 BOM:UTF-8 文件带 BOM 时,
read_xml()会把 BOM 当作非法字符报错;用xxd file.xml | head看开头是不是ef bb bf - 临时改用
read_xml()的重载版本,传入boost::property_tree::xml_parser::trim_whitespace和boost::property_tree::xml_parser::no_concat_text减少预处理干扰
怎么保留 XML 属性和文本混排(比如 <tag attr="x">text</tag>)?
Boost.PropertyTree 天然不区分“元素内容”和“属性”,它把所有东西都映射成键值对树。默认行为会把文本内容塞进一个叫 <xmlattr></xmlattr> 的伪节点下,而真实文本内容放在同级的 <xmltext></xmltext> 节点里 —— 这个设计反直觉,但必须接受。
例如这段 XML:
<item id="123">hello</item>
会被解析成:
item.<xmlattr>.id = "123" item.<xmltext> = "hello"
- 写入时也得按这个结构组织
ptree,不能直接pt.put("item", "hello"),否则属性会丢 - 想读取属性:用
pt.get_child("item.<xmlattr>").get_value("id")</xmlattr> - 想读取文本:用
pt.get_child("item.<xmltext>").get_value("")</xmltext>(注意 fallback 值要给空字符串,否则可能抛异常) - 别手动生成
<xmlattr></xmlattr>节点名:它是硬编码的,大小写敏感,拼错就查不到
用 ptree 处理大 XML 文件会卡死或爆内存吗?
会。PropertyTree 是全内存加载模型,没有流式解析能力。一个 50MB 的 XML 文件很可能吃掉 200MB+ 内存,且解析时间非线性增长。
这不是 bug,是设计限制 —— 它本就不是为大数据 XML 设计的。
- 如果文件 > 1MB,优先考虑
libxml2或pugixml;PropertyTree 只适合配置文件、小数据交换 - 即使小文件,也要防意外:用
try/catch包住read_xml(),因为解析失败时异常类型是boost::property_tree::xml_parser::xml_parser_error,不是标准std::exception - 释放内存:
ptree析构会清空,但若中间做了大量put()和add(),树深度过大,递归析构可能栈溢出(少见但存在)
真正麻烦的是混合场景:既要读写简单配置,又偶尔要啃几 MB 的 XML 日志。这时候别硬扛,该切库就切库,PropertyTree 的边界比很多人想的窄得多。










