libxml2在C中易出错的三大关键点是环境配置、编码处理和内存释放;需用apt安装开发包、显式指定头文件与链接库路径、检查返回值并用xmlFree()释放内存、将非UTF-8编码XML转为UTF-8、启用xmlIndentTreeOutput实现格式化输出、务必调用xmlCleanupParser()防止内存泄漏。
libxml2 在 C 中使用不难,但容易卡在环境配置、编码处理和内存释放三处——多数“段错误”或“中文乱码”都源于此。
Ubuntu/Debian 下最稳的方式是用包管理器装开发包,而非手动编译源码,除非你明确需要特定版本或静态链接:
sudo apt-get install libxml2-dev —— 自动安装头文件(/usr/include/libxml2/libxml/)和动态库(libxml2.so)gcc test.c -o test -I /usr/include/libxml2 -lxml2
/usr/local,需额外加 -L/usr/local/lib 并设置 LD_LIBRARY_PATH=/usr/local/lib,否则运行时报 error while loading shared libraries: libxml2.so.2: cannot open shared object file
别直接调 xmlReadFile() 就开干。libxml2 默认保留空白节点、不自动缩进,且不校验编码,出错后不清理会泄漏内存:
xmlKeepBlanksDefault(0) 去掉无意义的换行/空格文本节点xmlReadFile("test.xml", NULL, XML_PARSE_NOBLANKS) 更可靠,比只靠全局开关更明确doc 为 NULL 表示解析失败(常见于编码非 UTF-8、格式非法)xmlNodeGetContent() 返回的是 xmlChar*,必须用 xmlFree() 释放,不能用 free() 或忽略#include#include #include int main() { xmlDocPtr doc; xmlNodePtr root; xmlKeepBlanksDefault(0); // 关键:提前调用 doc = xmlReadFile("data.xml", NULL, XML_PARSE_NOBLANKS); if (!doc) { fprintf(stderr, "Parse failed\n"); return 1; } root = xmlDocGetRootElement(doc); if (!root) { fprintf(stderr, "Empty document\n"); xmlFreeDoc(doc); return 1; } xmlChar *content = xmlNodeGetContent(root); if (content) { printf("Root content: %s\n", content); xmlFree(content); // 必须! } xmlFreeDoc(doc); // 必须! xmlCleanupParser(); // 必须!多线程下尤其重要 return 0; }
libxml2 内部只认 UTF-8。如果你的 XML 文件是 GBK/GB2312 编码,xmlReadFile() 会解析失败或内容错乱,且不会报明确错误。
iconv -f GBK -t UTF-8 input.xml > input_utf8.xml
xmlReadMemory() 配合 libiconv 手动转码后再传入,但代码量翻倍,易出错xmlSaveFormatFileEnc("out.xml", doc, "GBK") 仅支持已内置编码名(如 UTF-8、ISO-8859-1),GBK 不在白名单里,强行写会导致保存失败或乱码默认生成的 XML 是一行到底,可读性差。启用格式化输出只需两步:
xmlIndentTreeOutput = 1(全局开关,必须在创建节点前设)xmlSaveFormatFile("out.xml", doc, 1),最后一个参数 format=1 才生效\n(非 \r\n),鸿蒙/Windows 下显示可能略别扭,但内容完全合法最常被跳过的其实是 xmlCleanupParser() —— 它释放内部全局缓存(比如 DTD 缓存),不调用的话,重复解析多个文件会缓慢增长内存;在守护进程或长期运行服务中,漏掉这句等于埋雷。