引言
expat是使用C语言编写的XML解析器,采用stream的方式解析XML文件,首先需要向解析器注册callback函数,在传入文档进行解析的时候,对于解析器能够识别的部分,就会去调用适当的callback动作进行解析。
被解析的xml文件是被分块传入解析器的,这样expat就能够解析较大的xml文件,而不需要将整个xml文件整个加载到内存中去。
具体的使用流程
- 创建解析器
XML_Parser XML_ParserCreate(const XML_Char* encoding)
//创建一个新的解析器,并返回一个解析器句柄
- 为开始和结束设置handler
XML_SetElementHandler(XML_Parser p, XML_StartElementHandler start, XML_EndElementHandler end);
typedef void (*XML_StartElementHandler) (void *userData, const XML_Char *name, const XML_Char **atts);
typedef void (*XML_EndElementHandler) (void *userData, const XML_Char *name);
解析器创建之后,stream需要先去设置callback,XML_SetElementHandler函数用来设置开始和结束标签的handlers
第一个参数是parser的操作句柄,第二个和第三个参数是callback函数用于解析到<></>
typedef void (*XML_StartElementHandler) (void *userData, const XML_Char *name, const XML_Char **atts);
//第一个参数需要使用函数XML_SetUserData(XML_Parser parser,void *p)
//后边的两个参数为name 和 atts
例如有一个XML文档
<feed version="2.0" ctxt-id="9212" template-id="default" feed-type="ftti">
</feed>
name返回的值就是feed
atts为指针数组atts[0] = "version" , atts[1] = "2.0"
typedef void (*XML_EndElementHandler) (void *userData, const XML_Char *name);
这个函数返回的name也是feed,处理标签结束。
- 设置文本buffer块handler
XML_SetCharacterDataHandler(XML_Parser p,XML_characterDataHandler charhnd1)
//这个函数用来处理一个<></>之间的字段回调,
//回调函数原型
typedef void (*XML_CharacterDataHandler)(void *userData, const XML_Char *s, int len);
这里的XML_CHAR *s是一块buffer的指针
<title>天气</title>
<summary>28日08时至29日08时,陕西中南部、山西西南部、河南中南部、湖北北部、四川中
东部、重庆西部和北部、贵州西部等地的部分地区有大雨或暴雨,河南南部、湖北北部等地局部
有大暴雨。【点击“更多”查询其他城市天气】</summary>
//以上就是指针指向的全部内容
传入字符开始解析Parse
int XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
/*XML_Parse函数用来实时侧传入字符解析Parse,第二个参数是用户指定的buffer指针,第三个参数是buffer中实际内容的字节数,最后的参数代表这块buffer是否已经结束
(例如每次需要读取到内存中的buffer比较小,就可以采用循环读取的方式,把文件中读出来的buffer都给parser中,在文件读取结束之前,isFinal的参数为FALSE,反之为TRUE)。*/
//这样会造成的问题就是,XML_CharacterDataHandler一次返回的不是一个完成的charData,这样就会连续的调用两次XML_CharacterDataHandler,再将两次返回的结果拼接起来。
开始解析parse的另一种方法
void *XML_GetBuffer(XML_Parser p,int len)
int XML_ParseBuffer(XML_Parser p,int len, int isFinal)
//使用示例
void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
if (buff == nullptr) {
MODEM_CTRLLOGE("failed in call to XML_GetBuffer");
return -1;
}
int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
if (bytes_read < 0) {
MODEM_CTRLLOGE("failed to read");
return -1;
}
XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
if (status == XML_STATUS_OK) {
MODEM_CTRLLOGE("%s", ::XML_ErrorString(::XML_GetErrorCode(parser)));
mParsingStatus = ERROR_MALFORMED;
return -1;
}
cacution:
XML_ParserReset(XML_Parser parser, const XML_Char *encodingname)
解析完一次xml文件之后,最好调用本函数完成重置xml