expatXML解析器
⼯作中⽤到了EXPAT,为了以后查询⽅便,把⽹上搜索到的内容综合整理如下。
win32 plat下的c/c++下使⽤expat。
expat是基于sax来进⾏xml解析⽽不是dom解析。因此,在expat中设置了很多的回调来处理。
XML_SetCharacterDataHandler(p,charhandler);
XML_SetElementHandler(p, start, end);
for (;;) {
int done;
int len;
len = fread(Buff, 1, BUFFSIZE, stdin);
if (ferror(stdin)) {
fprintf(stderr, "Read error\n");
exit(-1);
}
done = feof(stdin);
if (XML_Parse(p, Buff, len, done) ==XML_STATUS_ERROR) {
fprintf(stderr, "Parse error at line%" XML_FMT_INT_MOD "u:\n%s\n",
XML_GetCurrentLineNumber(p),
XML_ErrorString(XML_GetErrorCode(p)));
exit(-1);
}
printf( " depth = %d \n",Depth);
if (done)
break;
}
return 0;
}
其中XML_SetElementHandler设置回调,处理element节点;XML_SetCharacterDataHandler设置回调⽤于处理text节点⼀般来说有了这两个我们就可以处理了,例如下⾯的⼀个xml⽂件
<?xml version="1.0"?>
<xmlRoot price="">
<YEAR Now="2005">
<QUARTER1>2005</QUARTER1>
</YEAR>
</xmlRoot>
处理到xmlRoot节点的时候,会调⽤XML_SetElementHandler设置的回调函数,我们可以从回调函数中获取节点名称,节点的
属性列表,包括各个属性名称和对应的属性值。这⾥就可以获取到⼀个属性price,值为空。
继续下⾯的处理,当处理到QIARTER1时,会调⽤XML_SetCharacterDataHandler设置的回调函数获取text节点值。
char buf[100]={0};
static void XMLCALL charhandler(void *userData,const XML_Char *s, int len)
{
if(len!=0)
{
memcpy(buf,s,len);
buf[len] = '\0';
rintf("%s " ,buf);
}
}
注意,这⾥的s不是以\0结束的。
本⽂介绍expat 解析xml的基本⽅法,如果你希望⽤最轻量的解析器,请选择TinyXML,它更简单。
使⽤expat的原因很多,主要还是因为expat更灵活。习惯了TinyXML,⼀开始不太习惯expat,分析⼀下,其实很容易上⼿的。
1.回调函数
以下案例解析xml⽂件中的elment,attribute和text。expat使⽤回调⽅式返回xml数据,解析器解析到⼀个element及其内部属性后,将调⽤事先设置好的函数,同样,当element结束和text结束后,也会分别调⽤对应的函数。
2.如何处理数据之间的包含关系
典型的⽅式是定义三个函数分别处理elment开始(含属性)、element结束和⽂本内容。回调函数的第⼀个参数是⾃定义的,通常⽤于存储XML⽂档的上下⽂信息,⽤XML_SetUserData可以设置这个参数,下例中传递⼀个整数指针,以便在每次回调时能知道该元素是第⼏层元素。
该参数也可以是⼀个栈对象的地址,开始⼀个元素时,将新元素对应的数据压⼊堆栈,处理下⼀级元素时,新元素是栈顶元素在⼦元素,然后处理完了继续把该元素压⼊堆栈,继续下⼀级新的⼦元素。当元素结束后,需要出栈,以便解析下个兄弟元素程时能取到⽗节点。
好啦,基本应⽤还是很简单的,实际上Expat的API函数不多。
3.如何处理属性
属性通过ElementHandler回调函数传⼊,这⾥有⼀个char** atts就是属性,这是⼀个字符指针数组,如果有N个属性,数组⼤⼩就是
2*N+1,最后⼀个素组元素为空指针,奇数指针对应属性名称,偶数指针对应属性值(字符串格式)。可以在⼀个循环中处理多个属性,当遇到空指针时,表⽰没有更多属性了。
好啦,先看sample吧:
#include <stdio.h>
#include "expat.h"
#pragma warning(disable:4996)
#define XML_FMT_INT_MOD "l"
staticvoid XMLCALL startElement(void *userData, const char *name, const char **atts) {
int i;
int *depthPtr = (int *)userData;
for (i = 0; i < *depthPtr; i++)
printf(" ");
parse error怎么解决printf(name);
*depthPtr += 1;
for(i=0;atts[i]!=0;i+=2)
{
printf(" %s=%s",atts[i],atts[i+1]);
}
printf("\n");
}
staticvoid XMLCALL endElement(void *userData, const char *name)
{
int *depthPtr = (int *)userData;
*depthPtr -= 1;
}
int main(int argc, char *argv[])
{
char buf[BUFSIZ]; XML_Parserparser = XML_ParserCreate(NULL);
int done; int depth = 0;
XML_SetUserData(parser, &depth);
XML_SetElementHandler(parser, startElement,endElement);
FILE* pFile= argc<2 ?stdin : fopen(argv[1],"rb");
do
{ int len = (int)fread(buf, 1, sizeof(buf), pFile);
done = len < sizeof(buf);
if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR)
{
fprintf(stderr,"%s at line %"XML_FMT_INT_MOD "u\n",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
return1;
}
}
while (!done);
XML_ParserFree(parser);
XML_ParserFree(parser);
fclose(pFile);
return0;
}
4.其他ElementHanlder
expat还可以设置CData,Comment的handler,另外⼀些函数本⼈还没使⽤过,涉及到更多的xml标准的知识,如果需要,可以参考官⽅的⼿册。
参考:
要了解如何使⽤expat XML解析器之前,先来仔细地分析⼀下怎么样使⽤expat库的⼩例⼦,看看具体调⽤了那些接⼝函数,是否会很复杂的呢?‘它的例⼦程序如下:
#001
#013
#014
下⾯包括输出⽂件和库⽂件头。
#015 #include<stdio.h>
#016 #include"xmlparse.h"
#017
定义缓冲区的⼤⼩。
#018 #defineBUFFSIZE 8192
#019
创建⼀个缓冲区。
#020 charBuff[BUFFSIZE];
#021
#022 int Depth;
#023
下⾯定义⼀个XML元素开始处理的函数。
#024 void
#025 start(void*data, const char *el, const char **attr) {
#026 int i;
#027
#028 for (i = 0; i < Depth; i++)
#029 printf("");
#030
#031 printf("%s", el);
#032
#033 for (i = 0; attr[i]; i += 2) {
#034 printf("%s='%s'", attr[i], attr[i + 1]);
#035 }
#036
#037 printf("\n");
#038 Depth++;
#039 }
#040
下⾯定义⼀个XML元素结束调⽤的函数。
#041 void
#042 end(void*data, const char *el) {
#043 Depth--;
#043 Depth--;
#044 }
#045
程序⼊⼝点。
#046 void
#047 main(int argc,char **argv) {
创建⼀个XML分析器。
#048 XML_Parser p =XML_ParserCreate(NULL);
下⾯判断是否创建XML分析器失败。
#049 if (! p) {
#050fprintf(stderr, "Couldn't allocate memory for parser\n");
#051 exit(-1);
#052 }
#053
下⾯设置每个XML元素出现和结束的处理函数。这⾥设置start为元素开始处理函数,end元素结束处理函数。#054XML_SetElementHandler(p, start, end);
#055
循环分析所有XML⽂件。
#056 for (;;) {
#057 int done;
#058 int len;
#059
调⽤函数fread从⽂件⾥读取数据到缓冲区Buff⾥。
#060 len =fread(Buff, 1, BUFFSIZE, stdin);
读取⽂件出错就退出。
#061 if(ferror(stdin)) {
#062fprintf(stderr, "Read error\n");
#063 exit(-1);
#064 }
判断是否读取⽂件到结束。
#065 done =feof(stdin);
#066
调⽤库函数XML_Parse来分析缓冲区Buff⾥的XML数据。
#067 if (!XML_Parse(p, Buff, len, done)) {
#068fprintf(stderr, "Parse error at line %d:\n%s\n",
#069XML_GetCurrentLineNumber(p),
#070XML_ErrorString(XML_GetErrorCode(p)));
#071 exit(-1);
#072 }
#073
如果分析⽂件到结尾位置,或者出错,就可以退出循环处理。
#074 if (done)
#075 break;
#076 }
#077 }
#078
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论