pugixml是解析Doxygen生成XML的最优选,因其轻量、UTF-8原生支持、迭代器遍历高效,且能准确处理compounddef嵌套、memberdef作用域及refid跳转等关键结构。

Doxygen XML输出结构怎么看
Doxygen生成的XML不是为人工阅读设计的,而是给工具链消费的——节点嵌套深、命名机械(如 compounddef、memberdef)、大量冗余属性(id、kind、prot)。直接手写XPath或递归解析容易漏掉上下文依赖,比如一个 memberdef 的作用域由其父 compounddef 的 kind 决定(是 class 还是 namespace),而 name 字段可能被 ref 节点间接引用。
实际解析前务必确认 Doxygen 配置:GENERATE_XML = YES,且 XML_PROGRAMLISTING = NO(否则代码块会膨胀成巨量 sp/ref 节点,拖慢解析)。
用 pugixml 解析 XML 最简可行路径
pugixml 是 C++ 生态里最轻量、无依赖、API 清晰的 XML 库,比 libxml2 更适合做 Doxygen XML 的一次性提取。它不验证 schema,但 Doxygen XML 格式稳定,够用。
关键操作步骤:
立即学习“C++免费学习笔记(深入)”;
-
pugi::xml_document doc加载整个index.xml或单个compound_*.xml文件(不要全量加载所有 XML——内存爆炸) - 用
doc.child("doxygen").child("compounddef")定位根定义,再逐层.child()或.children("memberdef")遍历 - 取文本内容统一用
.child_value()(不是.text().get()),因为 Doxygen 在描述字段里常混用para、computeroutput等子节点 - 识别函数/变量需检查
memberdef的attribute("kind")值:是"function"、"variable"还是"enum"
示例:提取某个类中所有 public 函数签名
pugi::xml_node compound = doc.child("doxygen").child("compounddef");
for (pugi::xml_node m : compound.children("memberdef")) {
if (std::string(m.attribute("kind").value()) != "function") continue;
if (std::string(m.attribute("prot").value()) != "public") continue;
std::string name = m.child_value("name");
std::string type = m.child_value("type");
// 注意:参数列表在 <definition> 里(含返回类型和名),或拼 <type>+<name>+<argsstring>
}
为什么别用 tinyxml2 或 rapidxml
tinyxml2 的 XMLNode::FirstChildElement() 在面对 Doxygen 大量同名节点(如几十个 parameteritem)时性能明显劣于 pugixml 的迭代器遍历;rapidxml 要求内存缓冲区必须可写(Doxygen XML 文件 mmap 后只读会 crash),且不支持 XPath,写查找逻辑更啰嗦。
更现实的问题是编码:Doxygen 默认输出 UTF-8,但 Windows 上某些编译器默认窄字符流读取会把多字节当乱码。pugixml 的 load_file() 默认按 UTF-8 解析,无需额外转换;tinyxml2 则常要手动指定 TIXML_ENCODING_UTF8,漏掉就解析失败。
从 index.xml 入口跳转到具体 compound XML 的坑
index.xml 里每个 compound 节点只有 refid(如 "structfoo_1_1bar")和 kind,没有文件路径。真实路径是 refid + ".xml",但要注意:
- 文件名大小写敏感:Linux 下
structFoo.xml和structfoo.xml是两个文件 - Doxygen 可能启用
DISABLE_INDEX = YES,此时index.xml为空,必须扫描整个xml/目录找compound_*.xml -
refid中的下划线是命名空间分隔符(ns_1_1sub_1_1cls→ns::sub::cls),但文件系统路径不反映嵌套深度,一律扁平化
别指望靠 refid 反推头文件路径——Doxygen 不记录源码位置映射,除非开了 EXTRACT_ALL 并在 compounddef 里查 location 属性(且仅对定义有效,声明不带)。
真正麻烦的是跨文件符号引用:一个函数的 reimplements 属性指向另一个 refid,但目标 compounddef 可能在另一份 XML 里。缓存策略得自己做,不能边解析边 fopen/fclose。


















