如何学习expatxml parserr解析XML的代码

2343人阅读
expat下载地址:http://sourceforge.net/projects/expat/
互联网发得展很快,都是源自于使用了超文本的表达方式。比如你查看一篇文章,看到不懂的关键字,就可以通过链接去查看它的内容,看完之后再回来接着看原来的东西,这样比较适合学习的方式。使用HTML标记的文本,是结构化储存的,这样的表达方式才可以实现超级连接。由于HTML具有超强的表达能力,也就在互联网上生存下来,那么人们就会想到能不能使用这种方式来保存所有需要保存的内容呢?慢慢地就开发XML标记语言,用来保存任意想保存的内容。由于XML具有HTML同样的功能,并且不限定标记,这样就可以表达所有的东西了。并且XML是基于树形结构的,想表达的信息就可以采用归类树的方式来组织内容了,这样能产生灵活可变的内容管理方式。比如在第二人生里采用参数配置文件,也是选择XML来保存的,并且使用expat的XML解析器来实现这方面的内容。接着下来,我们就来了解一下expat是什么东东,又是怎么样调用它来解析XML文件的。 & expat是使用C编写的XML解释器,采用流的方式来解析XML文件,并且基于事件通知型来调用分析到的数据,并不需要把所有XML文件全部加载到内存里,这样可以分析非常大的XML文件。由于expat库是由XML的主要负责人James Clark来实现的,因此它是符合W3C的XML标准的。 & 使用expat库是非常简单的,只需要了解四个函数,就可以达到80%的功能了,看来设计这个库还是比较好的。那么需要了解那四个函数呢?这四个函数如下: XML_ParserCreate 创建一个XML分析器。 XML_SetElementHandler 设置处理标记开始和结束的处理函数。 XML_SetCharacterDataHandler 设置处理不同字符集的数据。 XML_Parse 分析给出的缓冲区XML数据。 通过调用上面四个函数就可以实现expat调用了,使用它就是这么方便简单的。
//无双 loveunix.net 转载请保留出处
#include &cstdlib&
#include &fstream&
#include &iostream&
#include &cstring&
#include &string&
#include &expat.h&
#define XML_MMSC_LISTEN_PORT
"MMSC_LISTEN_PORT"
#define XML_CLIENT_LISTEN_PORT
"CLIENT_LISTEN_PORT"
#define XML_MMSC_FROMADDR
"MMSC_FROMADDR"
#define XML_MMSC_IPADDR
"MMSC_IPADDR"
#define XML_MMSC_ROOT
"MMSC_ROOT"
#define XML_MMSC_PORT
"MMSC_PORT"
#define XML_MMSC_LOGIN_NAME
"MMSC_LOGIN_NAME"
#define XML_MMSC_LOGIN_PWD
"MMSC_LOGIN_PWD"
#define XML_MMSC_VASP_ID
"MMSC_VASP_ID"
#define XML_MMSC_VAS_ID
"MMSC_VAS_ID"
#define XML_MMS_SUBMIT_REPEATTIME "MMS_SUBMIT_REPEATTIME"
enum CONF_TYPE{EM_UNUSE = 0,
EM_LSN_MMSC_PORT,EM_LSN_CLN_PORT,EM_SENDREPEAT,
EM_MMSC_IP,EM_MMSC_PORT,EM_MMSC_ROOT,
EM_FROM,EM_VASPID,EM_VASID,
EM_AUTHNAME,EM_AUTHPWD
struct XML_MMSCConfInfo{
int MMSC_LISTEN_PORT;
int CLIENT_LISTEN_PORT;
char MMSC_FROMADDR[50];
char MMSC_IPADDR[16];
char MMSC_ROOT[255];
int MMSC_PORT;
char MMSC_LOGIN_NAME[255];
char MMSC_LOGIN_PWD[255];
char MMSC_VASP_ID[255];
char MMSC_VAS_ID[255];
int MMS_SUBMIT_REPEATTIME;
static int GetID(const char*name){
if(!stricmp(name,XML_MMSC_LISTEN_PORT))
return EM_LSN_MMSC_PORT;
if(!stricmp(name,XML_CLIENT_LISTEN_PORT))
return EM_LSN_CLN_PORT;
if(!stricmp(name,XML_MMSC_FROMADDR))
return EM_FROM;
if(!stricmp(name,XML_MMSC_IPADDR))
return EM_MMSC_IP;
if(!stricmp(name,XML_MMSC_ROOT))
return EM_MMSC_ROOT;
if(!stricmp(name,XML_MMSC_PORT))
return EM_MMSC_PORT;
if(!stricmp(name,XML_MMSC_LOGIN_NAME))
return EM_AUTHNAME;
if(!stricmp(name,XML_MMSC_LOGIN_PWD))
return EM_AUTHPWD;
if(!stricmp(name,XML_MMSC_VASP_ID))
return EM_VASPID;
if(!stricmp(name,XML_MMSC_VAS_ID))
return EM_VASID;
if(!stricmp(name,XML_MMS_SUBMIT_REPEATTIME))return EM_SENDREPEAT;
return EM_UNUSE;
static int SetElementValue(XML_MMSCConfInfo& Conf,const char*Value)
bool HasQoute =
const char*pstart = strchr(Value,'"');
const char*
if(!pstart){
pend = strchr( ++ pstart,'"');
if( !pend ) return -1;
int len = pend -
switch(Conf.Element){
case EM_LSN_MMSC_PORT:
Conf.MMSC_LISTEN_PORT
= atoi(pstart);
case EM_LSN_CLN_PORT:
Conf.CLIENT_LISTEN_PORT
= atoi(pstart);
case EM_SENDREPEAT:
Conf.MMS_SUBMIT_REPEATTIME=atoi(pstart);
case EM_MMSC_IP:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_IPADDR,pstart,len&sizeof(Conf.MMSC_IPADDR)
?sizeof(Conf.MMSC_IPADDR):len);
case EM_MMSC_PORT:
Conf.MMSC_PORT
= atoi(pstart);
case EM_MMSC_ROOT:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_ROOT,pstart,len&sizeof(Conf.MMSC_ROOT)?
sizeof(Conf.MMSC_ROOT):len);
case EM_FROM:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_FROMADDR,pstart,len&sizeof(Conf.MMSC_FROMADDR)?
sizeof(Conf.MMSC_FROMADDR):len);
case EM_VASPID:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_VASP_ID,pstart,len&sizeof(Conf.MMSC_VASP_ID)?
sizeof(Conf.MMSC_VASP_ID):len);
case EM_VASID:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_VAS_ID,pstart,len&sizeof(Conf.MMSC_VAS_ID)?
sizeof(Conf.MMSC_VAS_ID):len);
case EM_AUTHNAME:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_LOGIN_NAME,pstart,
len&sizeof(Conf.MMSC_LOGIN_NAME)?
sizeof(Conf.MMSC_LOGIN_NAME):len);
case EM_AUTHPWD:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_LOGIN_PWD,pstart,
len&sizeof(Conf.MMSC_LOGIN_PWD)?
sizeof(Conf.MMSC_LOGIN_PWD):len);
static void XMLCALL
xmlstart(void *data, const char *el, const char **attr)
XML_MMSCConfInfo* pmmscinf = (XML_MMSCConfInfo*)
for(int i = 0;attr[i];i++){
pmmscinf-&Element
= GetID(attr[i]);
SetElementValue(*pmmscinf,attr[i+1]);
pmmscinf-&Element
= GetID(el);
pmmscinf-&Depth ++;
static void XMLCALL
xmlend(void *data, const char *el)
((XML_MMSCConfInfo*)data)-&Element = EM_UNUSE;
((XML_MMSCConfInfo*)data)-&Depth
static void XMLCALL
parsedata(void *userData,const XML_Char *s,int len)
str.assign(s,len);
SetElementValue(*(XML_MMSCConfInfo*)userData,str.c_str());
解析MMSC配置文件
* @return -1失败0成功
static int ParseMMSCConf( XML_MMSCConfInfo& Conf ,const char*FileName)
memset(&Conf,0,sizeof(XML_MMSCConfInfo));
ifstream ifs(FileName,ios::in|ios::binary);
return -1;
ifs.seekg(0,ios::end);
len = ifs.tellg();
ifs.seekg(0,ios::beg);
buf = new char[len];
ifs.read(buf,len);
ifs.close();
return -1;
XML_Parser parser = XML_ParserCreate(NULL);
if( !parser ){
cerr&&"Couldn't allocate memory for parser"&&
return -1;
XML_SetElementHandler(parser,xmlstart,xmlend);
XML_SetUserData(parser,&Conf);
XML_SetCharacterDataHandler(parser,parsedata);
if (XML_Parse(parser, buf, len, done)
== XML_STATUS_ERROR) {
cerr&&XML_ErrorString(XML_GetErrorCode(parser))&&" at line "
&&XML_GetCurrentLineNumber(parser)&&
ifs.close();
XML_ParserFree(parser);
static Serialize(const XML_MMSCConfInfo& Conf)
printf("XML_MMSCConfInfo is:/n"
"/tDepth:%d/tElement:%d/n"
"/tMSC_LISTEN_PORT:%d/tCLIENT_LISTEN_PORT:%d/n"
"/tMMSC_FROMADDR:[%s]
MMSC_IPADDR:[%s]
tMMSC_PORT:%d/n"
"/tMMSC_ROOT:[%s]/tMSC_LOGIN_NAME:[%s]/tMMSC_LOGIN_PWD:[%s]/n"
"/tMMSC_VASP_ID:[%s]/tMMSC_VAS_ID:[%s]/tMMS_SUBMIT_REPEATTIME:%d/n",
Conf.Depth,
Conf.Element,
Conf.MMSC_LISTEN_PORT,
Conf.CLIENT_LISTEN_PORT,
Conf.MMSC_FROMADDR,
Conf.MMSC_IPADDR,
Conf.MMSC_PORT,
Conf.MMSC_ROOT,
Conf.MMSC_LOGIN_NAME,
Conf.MMSC_LOGIN_PWD,
Conf.MMSC_VASP_ID,
Conf.MMSC_VAS_ID,
Conf.MMS_SUBMIT_REPEATTIME);
void main()
XML_MMSCConfInfo
ParseMMSCConf(Conf,"conf.xml");
Serialize(Conf);
xml文件内容如下
&?xml version="1.0" encoding="gb2312" ?&
&mmscconf&
&MMSC_LISTEN_PORT&8801 &/MMSC_LISTEN_PORT&
&CLIENT_LISTEN_PORT&8902 &/CLIENT_LISTEN_PORT&
&MMSC_FROMADDR&"+1/TYPE=PLMN" &/MMSC_FROMADDR&
&MMSC_IPADDR&"172.16.65.187" &/MMSC_IPADDR&
&MMSC_ROOT&"/" &/MMSC_ROOT&
&MMSC_PORT&9000 &/MMSC_PORT&
&MMSC_LOGIN_NAME&"nan" &/MMSC_LOGIN_NAME&
&MMSC_LOGIN_PWD&"whuang" &/MMSC_LOGIN_PWD&
&MMSC_VASP_ID&"999999" &/MMSC_VASP_ID&
&MMSC_VAS_ID&"9999" &/MMSC_VAS_ID&
&MMS_SUBMIT_REPEATTIME&3 &/MMS_SUBMIT_REPEATTIME&
&/mmscconf&
使用expat时不会帮助检查xml语法 所以你必须保证要分析的xml文件是对的
expat默认只支持UTF-8 UTF-16 ISO-8859-1 US-ASCII 其它的字符集需要自己定义UnknownEncodingHandler的实现 不然分析器会报错
中文xml文件的处理 或是其它非标准编码xml文件的处理
expat内建只支持utf-8 ucs2 us-ascii iso8859-1 编码
其它的编码必须设置XML_SetUnknownEncodingHandler
* =====================================================================================
getinfo.cpp
Description:
使用expat开发xml例子程序,包括对中文xml的支持
15:17:34 中国标准时间
www.loveunix.net
* =====================================================================================
#include &cstdlib&
#include &fstream&
#include &iostream&
#include &cstring&
#include &string&
#include &windows.h&
#include &expat.h&
#define XML_MMSC_LISTEN_PORT
"MMSC_LISTEN_PORT"
#define XML_CLIENT_LISTEN_PORT
"CLIENT_LISTEN_PORT"
#define XML_MMSC_FROMADDR
"MMSC_FROMADDR"
#define XML_MMSC_IPADDR
"MMSC_IPADDR"
#define XML_MMSC_ROOT
"MMSC_ROOT"
#define XML_MMSC_PORT
"MMSC_PORT"
#define XML_MMSC_LOGIN_NAME
"MMSC_LOGIN_NAME"
#define XML_MMSC_LOGIN_PWD
"MMSC_LOGIN_PWD"
#define XML_MMSC_VASP_ID
"MMSC_VASP_ID"
#define XML_MMSC_VAS_ID
"MMSC_VAS_ID"
#define XML_MMS_SUBMIT_REPEATTIME "MMS_SUBMIT_REPEATTIME"
enum CONF_TYPE{EM_UNUSE = 0,
EM_LSN_MMSC_PORT,EM_LSN_CLN_PORT,EM_SENDREPEAT,
EM_MMSC_IP,EM_MMSC_PORT,EM_MMSC_ROOT,
EM_FROM,EM_VASPID,EM_VASID,
EM_AUTHNAME,EM_AUTHPWD
struct XML_MMSCConfInfo{
int MMSC_LISTEN_PORT;
int CLIENT_LISTEN_PORT;
char MMSC_FROMADDR[50];
char MMSC_IPADDR[16];
char MMSC_ROOT[255];
int MMSC_PORT;
char MMSC_LOGIN_NAME[255];
char MMSC_LOGIN_PWD[255];
char MMSC_VASP_ID[255];
char MMSC_VAS_ID[255];
int MMS_SUBMIT_REPEATTIME;
static int ConvertFromUTF8(char*strout,int stroutlen,
const char*Text,int TextLen)
转换utf-8编码到gb2312,linux下使用iconv函数可以直接转换,
在win下需要先转换到ucs2再从ucs2转换到utf-8
WCHAR WCharBuf[_MAX_PATH];
LPWSTR pTransBuf = WCharB
TransBufLen = _MAX_PATH;
if(TextLen&=_MAX_PATH){
TransBufLen = TextL
pTransBuf = new WCHAR[TransBufLen];
if(!pTransBuf)
length = MultiByteToWideChar(CP_UTF8,0,Text,TextLen,
pTransBuf,TransBufLen);
length = WideCharToMultiByte(CP_ACP,0,pTransBuf,length,
strout,stroutlen,NULL,NULL);
if(pTransBuf !=WCharBuf)
delete[] pTransB
static int GetID(const char*name){
if(!stricmp(name,XML_MMSC_LISTEN_PORT))
return EM_LSN_MMSC_PORT;
if(!stricmp(name,XML_CLIENT_LISTEN_PORT))
return EM_LSN_CLN_PORT;
if(!stricmp(name,XML_MMSC_FROMADDR))
return EM_FROM;
if(!stricmp(name,XML_MMSC_IPADDR))
return EM_MMSC_IP;
if(!stricmp(name,XML_MMSC_ROOT))
return EM_MMSC_ROOT;
if(!stricmp(name,XML_MMSC_PORT))
return EM_MMSC_PORT;
if(!stricmp(name,XML_MMSC_LOGIN_NAME))
return EM_AUTHNAME;
if(!stricmp(name,XML_MMSC_LOGIN_PWD))
return EM_AUTHPWD;
if(!stricmp(name,XML_MMSC_VASP_ID))
return EM_VASPID;
if(!stricmp(name,XML_MMSC_VAS_ID))
return EM_VASID;
if(!stricmp(name,XML_MMS_SUBMIT_REPEATTIME))return EM_SENDREPEAT;
return EM_UNUSE;
static int SetElementValue(XML_MMSCConfInfo& Conf,const char*Value)
bool HasQoute =
const char*pstart = strchr(Value,'"');
const char*
if(!pstart){
pend = strchr( ++ pstart,'"');
if( !pend ) return -1;
int len = pend -
switch(Conf.Element){
case EM_LSN_MMSC_PORT:
Conf.MMSC_LISTEN_PORT
= atoi(pstart);
case EM_LSN_CLN_PORT:
Conf.CLIENT_LISTEN_PORT
= atoi(pstart);
case EM_SENDREPEAT:
Conf.MMS_SUBMIT_REPEATTIME=atoi(pstart);
case EM_MMSC_IP:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_IPADDR,pstart,len&sizeof(Conf.MMSC_IPADDR)
?sizeof(Conf.MMSC_IPADDR):len);
case EM_MMSC_PORT:
Conf.MMSC_PORT
= atoi(pstart);
case EM_MMSC_ROOT:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_ROOT,pstart,len&sizeof(Conf.MMSC_ROOT)?
sizeof(Conf.MMSC_ROOT):len);
case EM_FROM:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_FROMADDR,pstart,len&sizeof(Conf.MMSC_FROMADDR)?
sizeof(Conf.MMSC_FROMADDR):len);
case EM_VASPID:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_VASP_ID,pstart,len&sizeof(Conf.MMSC_VASP_ID)?
sizeof(Conf.MMSC_VASP_ID):len);
case EM_VASID:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_VAS_ID,pstart,len&sizeof(Conf.MMSC_VAS_ID)?
sizeof(Conf.MMSC_VAS_ID):len);
case EM_AUTHNAME:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_LOGIN_NAME,pstart,
len&sizeof(Conf.MMSC_LOGIN_NAME)?
sizeof(Conf.MMSC_LOGIN_NAME):len);
case EM_AUTHPWD:
if( !HasQoute) return -1;
strncpy(Conf.MMSC_LOGIN_PWD,pstart,
len&sizeof(Conf.MMSC_LOGIN_PWD)?
sizeof(Conf.MMSC_LOGIN_PWD):len);
/*----------------------------------------------------------------------
xml解析函数,
以下参数说明
data是使用XML_SetUserData设置的参数,expat不进行处理,会把它交给用户回调函数处理
el是元素名
attr是属性-值列表,样子为attr[0]=attr[1],最后一个是NULL
*----------------------------------------------------------------------*/
static void XMLCALL
xmlstart(void *data, const char *el, const char **attr)
当碰到xml元素的开始标志时会调用这个函数,可以看打印显示的结果
printf("start element:
sax是Simple API for XML
Megginson采用Java语言开发的,之后SAX很快在Java开发者中流行起来。SAN项目现在负责管理其原始API的开发工作,这是一种公开的、开放源代码软件。不同于其他大多数XML标准的是,SAX没有语言开发商必须遵守的标准SAX参考版本。因此,SAX的不同实现可能采用区别很大的接口。不过,所有的这些实现至少有一个特性是完全一样的,这就是事件驱动。事件驱动的文档解析在SAX解析器装载XML文件时,它遍历文件文档并在其主机应用程序中产生事件(经由回调函数、指派函数或者任何可调用平台完成这一功能)表示这一过程。这样,编写SAX应用程序就如同采用最现代的工具箱编写GUI程序。大多数SAX实现都会产生以下若干类型的事件:*在文档的开始和结束时触发文档处理事件。*在文档内每一XML元素接受解析的前后触发元素事件。任何元数据通常都由单独的事件交付。*在处理文档的DTD或Schema时产生DTD或Schema事件。*错误事件用来通知主机应用程序解析错误。显而易见,在处理文档时你最关心的就是元素事件了。通常,SAX解析器会向你的主机应用程序提供包含元素信息的事件参数;在最低程度下也会提供元素的名字。具体取决于你的特定实现,可以定义不同类型的元素事件代表不同类型元素的处理。例如,注释元素(它可能包含主机应用程序的处理指令)就经常在接受处理时产生特殊的事件。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:392494次
积分:5451
积分:5451
排名:第4704名
原创:136篇
转载:55篇
评论:108条
(6)(4)(3)(1)(1)(3)(9)(1)(4)(1)(3)(5)(3)(8)(3)(6)(3)(1)(1)(1)(1)(5)(1)(1)(2)(1)(5)(5)(4)(7)(2)(5)(9)(2)(9)(5)(1)(59)(1)1866人阅读
fbreader(5)
互联网发展得很快,都是源自于使用了超文本的表达方式。比如你查看一篇文章,看到不懂的关键字,就可以通过链接去查看它的内容,看完之后再回来接着看原来的东西,这样比较适合学习的方式。使用HTML标记的文本,是结构化储存的,这样的表达方式才可以实现超级连接。由于HTML具有超强的表达能力,也就在互联网上生存下来,那么人们就会想到能不能使用这种方式来保存所有需要保存的内容呢?慢慢地就开发XML标记语言,用来保存任意想保存的内容。由于XML具有HTML同样的功能,并且不限定标记,这样就可以表达所有的东西了。并且XML是基于树形结构的,想表达的信息就可以采用归类树的方式来组织内容了,这样能产生灵活可变的内容管理方式。比如在第二人生里采用参数配置文件,也是选择XML来保存的,并且使用expat的XML解析器来实现这方面的内容。接着下来,我们就来了解一下expat是什么东东,又是怎么样调用它来解析XML文件的。&expat是使用C编写的XML解释器,采用流的方式来解析XML文件,并且基于事件通知型来调用分析到的数据,并不需要把所有XML文件全部加载到内存里,这样可以分析非常大的XML文件。由于expat库是由XML的主要负责人James Clark来实现的,因此它是符合W3C的XML标准的。&使用expat库是非常简单的,只需要了解四个函数,就可以达到80%的功能了,看来设计这个库还是比较好的。那么需要了解那四个函数呢?这四个函数如下:XML_ParserCreate 创建一个XML分析器。XML_SetElementHandler 设置处理标记开始和结束的处理函数。XML_SetCharacterDataHandler 设置处理不同字符集的数据。XML_Parse 分析给出的缓冲区XML数据。通过调用上面四个函数就可以实现expat调用了,使用它就是这么方便简单的。
要了解第二人生里使用expat XML解析器之前,先来仔细地分析一下怎么样使用expat库的小例子,看看具体调用了那些接口函数,是否会很复杂的呢?&它的例子程序如下:#001 /*****************************************************************#002&& * outline.c#003&& *#004&& * Copyright 1999, Clark Cooper#005&& * All rights reserved.#006&& *#007&& * This prog you can redistribute it and/or#008&& * modify it under the same terms as Perl.#009&& *#010&& * Read an XML document from standard input and print an element#011&& * outline on standard output.#012&& */#013 #014 &下面包括输出文件和库文件头。#015 #include &stdio.h&#016 #include "xmlparse.h"#017 &定义缓冲区的大小。#018 #define BUFFSIZE&& 8192#019 &创建一个缓冲区。#020 char Buff[BUFFSIZE];#021 #022 int D#023 &下面定义一个XML元素开始处理的函数。#024 void#025 start(void *data, const char *el, const char **attr) {#026&&&#027 #028&&& for (i = 0; i & D 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 } /* End of start handler */#040 &下面定义一个XML元素结束调用的函数。#041 void#042 end(void *data, const char *el) {#043&&& Depth--;#044 } /* End of end handler */#045 &程序入口点。#046 void#047 main(int argc, char **argv) {&创建一个XML分析器。#048&&& XML_Parser p = XML_ParserCreate(NULL);&下面判断是否创建XML分析器失败。#049&&& if (! p) {#050&&&&& fprintf(stderr, "Couldn't allocate memory for parser/n");#051&&&&& exit(-1);#052&&& }#053 &下面设置每个XML元素出现和结束的处理函数。这里设置start为元素开始处理函数,end元素结束处理函数。#054&&& XML_SetElementHandler(p, start, end);#055 &循环分析所有XML文件。#056&&& for (;;) {#057&&&&&#058&&&&&#059 &调用函数fread从文件里读取数据到缓冲区Buff里。#060&&&&& len = fread(Buff, 1, BUFFSIZE, stdin);&读取文件出错就退出。#061&&&&& if (ferror(stdin)) {#062&&&&&&& fprintf(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)) {#068&&&&&&& fprintf(stderr, "Parse error at line %d:/n%s/n",#069&&&&&&&&& XML_GetCurrentLineNumber(p),#070&&&&&&&&& XML_ErrorString(XML_GetErrorCode(p)));#071&&&&&&& exit(-1);#072&&&&& }#073 &如果分析文件到结尾位置,或者出错,就可以退出循环处理。#074&&&&& if (done)#075&&&&&&&#076&&& }#077 } /* End of main */#078 #079 #080 &通过上面调用库函数XML_ParserCreate、XML_SetElementHandler、XML_Parse等三个函数就完成了XML的分析过程,这样使用起来真是太简单了,看到expat库的威力无穷。&如果需要了解更多关于expat库的内容,可以参考下面两个网站:
本文来自CSDN博客,转载请标明出处:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:413830次
积分:4738
积分:4738
排名:第5881名
原创:39篇
转载:142篇
评论:66条
(2)(1)(1)(1)(2)(2)(1)(2)(1)(2)(3)(9)(6)(1)(21)(39)(6)(1)(4)(4)(3)(1)(1)(8)(5)(29)(25)转自:http://blog.csdn.net/exclusivepig/article/details/4566252
expat是使用C所写的XML解释器,采用流的方式来解析XML文件,并且基于事件通知型来调用分析到的数据,并不需要把所有XML文件全部加载到内存里,这样可以分析非常大的XML文件。由于expat库是由XML的主要负责人James Clark来实现的,因此它是符合W3C的XML标准的。
---------------------------以上为转载-------------------------------------
正因为源码全部是纯C所写,因此,非常容易移植,尤其是适用于平台,我在往联芯的手机平台上移植时,几乎没改任何东西。
不过,优点也带来了缺点,因为是采用流的方式解析XML,所以不会像TinyXML那样在一块内存中生成基于DOM的树。
虽然这样解析起来略显麻烦,但是基于回调的机制,在我看来还是蛮方便的。
下面就说使用方法:
首先是用XML_ParserCreate(const&XML_Char&*encodingName),参数一般为NULL,函数返回一个XML_Parser类型指针,我们就当他是一个句柄吧,类似于Windows里的内核对象,一般需要保存在一个全局的指针里。
然后调用XML_SetElementHandler(XML_Parser&parser,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&XML_StartElementHandler&start,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&XML_EndElementHandler&end)
&&&&&&&&&第一个参数是那个Parser句柄,第二个和第三个参数则是整个Parser的核心,类型为CallBack的函数,不了解CallBack函数的,我在这里简单说下,函数调用一般分为两种,一种是主调,即编写代码者,自己调用的函数,还一种成为Callback函数,编码者写好,但他自己却不主动调用,而是在某些条件下(编码者并不清楚具体时间和流程),由其他函数调用,比如简单的,如设备驱动,提供了一组某个设备的函数指针,比如LCD屏驱动,由一组画点,画线,画块等函数组成,当更换LCD时,只需要把操作系统开放的函数指针,指向你提供的接口即可,操作系统再需要时,会自动调用你的驱动函数,这就是回调函数一个典型的例子。
&&&&&&&这二个回调分别是对应于解析&&和&/&, 下面分别详细介绍这个2个回调函数。
&&&&&&&typedef&void&(XMLCALL&*XML_StartElementHandler)
(void&*userData,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&const&XML_Char&*name,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&const&XML_Char&**atts);
&&&&&&&其中第一个参数userData, 可以由函数XML_SetUserData(XML_Parser&parser,&void&*p)设置,参数就不用说了吧?
&&&&&& 后面两个参数,我用个具体的列子说明下,这样更好理解:
&&&&&& 比如有个标准XML,某个标签属性如下:
&&&&&& &feed version=&2.0& ctxt-id=&9212& template-id=&default& feed-type=&ftti&&
&&&&&&&那么StartElementHandler回调返回的name就是标签&feed&,&**atts是一个指针数组,分别指向标签的一组属性,atts[0]就是&version&,&atts[1]就是&2.0&,
以此类推。应该很清楚了吧?呵呵。
&&&&&&&这时候必然有个对应的&/feed&,
&&&&&&&typedef&void&(XMLCALL&*XML_EndElementHandler)
(void&*userData,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&const&XML_Char&*name);
&&&&&& 就是处理标签结束的,name就是&feed”了,这个回调一般是用户设置自己的状态机的。
&&&&&&&最后一个函数就是XML_SetCharacterDataHandler(XML_Parser&parser,XML_CharacterDataHandlerhandler)
&&&&&& 这个函数是设置处理一个&&和&/&之间的字段的回调。
&&&&&& 回调原型如下:
&&&&&&&typedef&void&(XMLCALL&*XML_CharacterDataHandler)
(void&*userData,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&const&XML_Char&*s,&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&int&len);
&&&&&&&其中第二个参数是一块Buffer的指针,如果你单步DEBUG后,你会发现expat用的就是你传入的那块Buffer(这块Buffer下面讲解),比如:
&&&&&&&&title&天气&/title&
&&&&&& &summary&28日08时至29日08时,陕西中南部、山西西南部、河南中南部、湖北北部、四川中东部、重庆西部和北部、贵州西部等地的部分地区有大雨或暴雨,河南南部、湖北北部等地局部有大暴雨。【点击“更多”查询其他城市天气】&/summary&
&&&&&& 假设目前解析到天气这个charData, 如果你看那个指针的所有内容的话,实际上是这样的:
&&&&&&&天气&/title&
&&&&&& &summary&28日08时至29日08时,陕西中南部、山西西南部、河南中南部、湖北北部、四川中东部、重庆西部和北部、贵州西部等地的部分地区有大雨或暴雨,河南南部、湖北北部等地局部有大暴雨。【点击“更多”查询其他城市天气】&/summary&
&&&&&& 所有要根据第三个参数len来确定正确的数据。
&&&&&& 但这里有个非常隐晦的问题,如果不知道的话,会带来很大麻烦,下面说。
&&&&&&&最后就是parse,调用
&&&&&&&XML_Parse(XML_Parser&parser,&const&char&*s,&int&len,&int&isFinal)
&&&&&&&第二个参数是用户指定的Buffer指针, 第三个是这块Buffer中实际内容的字节数,最后参数代表是否这块Buffer已经结束。比如要解析的XML文件太大,但内存比较吃紧,Buffer比较小,则可以循环读取文件,然后丢给Parser,& 在文件读取结束前,isFinal参数为FALSE,反之为TRUE。
&&&&&&这里的Buffer如果太小则会造成上面提到那个隐晦的问题,
&&&&&&XML_CharacterDataHandler一次返回的可能并不是完整的CharData,比如这个charData的Len大于你的Buffer大小,那这是会连续调用2次XML_CharacterDataHandler,我们需要将2次结果拼接起来,以得到正确结果,因此我们的状态机一定要考虑到这点。
&&&&& 顺便说下XML_ParserReset(XML_Parser&parser,&const&XML_Char&*encodingName)函数,在某些时候,如果你不确定前后2次XML是否一样的情况下,比如网络上投递的XML,在一次解析后最好调用一次本函数,否则会出现意料之外的结果。比如前后两次XML完全一样,可这你并不知情,那么XML_Parse()会返回失败。
&&&&& 好了,开源的XML解析器expat就讲到这,下次说开源的SQLsqlite3的移植和使用心得。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6063次
排名:千里之外
原创:13篇
转载:36篇
(1)(6)(2)(7)(3)(21)(3)(6)(1)(1)

我要回帖

更多关于 htmlparser 的文章

 

随机推荐