expat是纯c轻量级流式xml解析器,不建dom、不占内存,适合大文件、嵌入式和低延迟场景;属性需安全遍历atts数组,分块解析需正确设isfinal,复用解析器须调xml_parserreset,编码需显式指定。

为什么选 Expat 而不是 libxml2 或 tinyxml?
如果你要解析的是大文件(比如几百 MB 的日志 XML)、嵌入式设备(内存紧张)、或需要低延迟响应(如实时配置热更新),Expat 是更稳妥的选择。libxml2 功能全但体积大、默认走 DOM;tinyxml 是 C++ 的,不满足纯 C 场景。
-
XML_ParserCreate创建的解析器本身只占几 KB 内存 - 没有
#include <string></string>、std::vector等 C++ 依赖,编译产物干净 - 不验证 DTD 或 XSD,默认只做 well-formed 检查,开销极小
XML_SetElementHandler 和属性数组怎么安全取值?
Expat 把属性传成 const XML_Char **atts,本质是“名值对”连续排列的扁平数组:[name1, value1, name2, value2, NULL]。很多人直接 atts[0] 取第一个属性名,但忘了判空或越界——一旦 XML 缺少属性或格式异常,就会崩。
- 必须循环检查
atts[i] != NULL,且每次取atts[i]和atts[i+1]前确保i+1有效 - 不要假设属性顺序,
<item id="1" type="json"></item>中atts[0]不一定是"id" - 如果要用
strcmp(atts[i], "host") == 0匹配,记得i步进是2
解析大文件时 XML_Parse 怎么分块传入?
不能一次性把整个文件 fread 到 buffer 再调用一次 XML_Parse——这等于放弃流式优势,还可能因 buffer 不够大而截断标签。正确做法是循环读、分段喂给解析器,并用 isFinal 参数标识结尾。
本文档主要讲述的是使用JSON进行网络数据交换传输;JSON(JavaScript ObjectNotation)是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成,非常适合于服务器与客户端的交互。JSON采用与编程语言无关的文本格式,但是也使用了类C语言的习惯,这些特性使JSON成为理想的数据交换格式。 和 XML 一样,JSON 也是基于纯文本的数据格式。由于 JSON 天生是为 JavaScript 准备的,因此,JSON的数据格式非常简单,您可以用 JSON 传输一个简单的 St
- 每次
fread(buf, 1, BUFSIZ, fp)后,调用XML_Parse(parser, buf, len, feof(fp)) -
isFinal = 1只能在最后一次调用时设为真,否则解析器会提前终止并报错XML_ERROR_ABORTED - 若从网络 socket 读,需自己管理粘包,保证 UTF-8 多字节字符不被切开(Expat 不自动缓冲)
XML_ParserReset 什么情况下必须调用?
当你想复用同一个 XML_Parser 句柄解析多个 XML 片段(比如一个 TCP 连接里连续发来多个 XML 消息),就必须在每次新解析前调用 XML_ParserReset。否则残留状态(如未闭合的元素栈、编码上下文)会导致后续解析失败或回调错乱。
立即学习“C语言免费学习笔记(深入)”;
- 错误写法:
XML_Parse(p, xml1, ...); XML_Parse(p, xml2, ...);—— 第二个会出错 - 正确写法:
XML_Parse(p, xml1, ..., 1); XML_ParserReset(p, NULL); XML_Parse(p, xml2, ..., 1); -
XML_ParserReset不释放内存,所以不用重复XML_SetElementHandler,但XML_SetUserData需重设(如果 userData 指向栈变量)
XML_ParserCreate("GBK") 或转码,解析会静默失败——既不报错也不触发回调,只会卡在第一个标签。









