不该自己写xml解析器,因xml规范复杂(含命名空间、实体引用、cdata等),手写易在边界情况崩溃;应优先使用pugixml等成熟库,其轻量、安全、易用。

为什么不该自己写 XML 解析器
绝大多数场景下,std::string 拼接 + 正则匹配或手写递归下降解析器,既不可靠也难以维护。XML 规范包含命名空间、CDATA、实体引用(&、)、注释、处理指令、编码声明等,哪怕只支持 UTF-8 且忽略 DTD,<code>tinyxml2 或 pugixml 的轻量级 C++ 库已足够,自己实现容易在边界 case 上崩溃——比如遇到 (Unicode RTL 控制符)或嵌套很深的 <tag><tag><tag></tag></tag></tag> 导致栈溢出。
用 pugixml 解析单层结构最简路径
pugixml 头文件仅一个 pugixml.hpp,无依赖,编译快,适合嵌入式或命令行工具。它默认禁用外部实体加载(安全),且 load_string() 接口直接接受 C 风格字符串,避免 std::string 生命周期干扰。
常见错误现象:doc.load_string(xml.c_str()) 返回 false 却没检查;或用 child("item") 时未确认节点存在就调用 attribute("id").as_int() 导致静默返回 0。
- 始终检查
load_*返回值:if (!doc.load_string(xml.c_str())) { /* 处理 parse_error */ } - 用
child_value()取文本内容,比child().text().get()更安全(自动跳过空白文本节点) - 属性访问前先用
attribute("attr_name").empty()判断是否存在,否则.as_int()默认返回 0,易掩盖缺失字段 - 若 XML 含中文,确保源字符串是 UTF-8 编码(Windows 下读文件需用
std::ifstream配合std::codecvt_utf8或直接用load_file())
手写简易解析器只适用于严格受控格式
如果 XML 是你完全控制的输出(如配置文件生成器固定输出 <config><port>8080</port><debug>true</debug></config>),可基于状态机跳过标签、提取内容。但必须明确放弃以下能力:
- 不处理嵌套:只支持单层标签,
<a><b>val</b></a>会失败 - 不转义:输入含
<时,不会还原为 - 不校验闭合:遇到
<tag>text</tag>结尾无不报错 - 属性全忽略:只认
<tag>content</tag>形式,无视<tag attr="v"></tag>
核心逻辑就是扫描 → 跳过标签名 → 找到 <code>> → 记录起始位置 → 找下一个 作为结束。用 <code>std::string::find() 和 substr() 就够,但别叫它“XML 解析器”,叫“标签提取器”更准确。
性能与兼容性取舍点
pugixml 默认使用 DOM 模式,内存占用随文档大小线性增长;若 XML 超过几十 MB,应切换到 SAX 模式(pugi::xml_parse_result + 自定义 xml_tree_walker),但开发成本陡增。而 tinyxml2 的 DOM 性能略低,但 API 更接近 Java 的 DocumentBuilder,新手上手快。
真正容易被忽略的是编码:C++11 后 std::string 本身不携带编码信息,pugixml 假设输入为 UTF-8。若原始数据是 Windows-1252 或 GBK,必须先转码,否则 child("中文标签") 查不到节点——因为内部用 strcmp 比较字节序列,而非 Unicode 码点。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











