基于Linux C的聊天室客户端(二)libxml2的使用

接上回,

上次说到协议使用XML格式的,就是为了能够比较好的通过已有的函数库来解析,那在JAVA里常用的就是DOM4J,在C里笔者这次用的是libxml2,官方地址是:http://xmlsoft.org/ 可以下载和查看API文档。

libxml2要先安装了才能使用,笔者是直接用yum安装的,如果想手动装的话就可以看看这篇博文:

http://blog.csdn.net/shanzhizi/article/details/7726679

这次大作业是用VirtualBox虚拟了一个CentOS 6.5出来完成的,如果和笔者用的系统一样呢,那就可以参考一下这个使用方法,当使用了libxml2的函数后,在用GCC编译的时候要这样写:

gcc -I/usr/include/libxml2/ -lxml2 xxx.c

否则由于动态库和头文件找不到的原因会导致无法编译通过。

接下来就以通知的解析过程(int sendMessage)为例来具体说一下libxml2的简单使用:

XML文档解析的基本模型都是类似的,先是Document ,Document 里先找到Root Element 找到Root Element 后再依次解析下面的各个Node 。所以先要有一个Document 的指针,这个struct 叫xmlDocPtr ,然后需要一些Node 的指针, 一般而言两个就可以了,一个是root记录根节点, 另一个是curr记录当前节点。为了方便,笔者用了比较多。

// xml文档指针xmlDocPtr pdoc;// xml 节点指针xmlNodePtr root, room, information, code, messages, detail;

先要发送请求字符串,然后从服务器获取字符串,这个过程之后再写,现在先写获得之后做的事,获得之后是一个字符串,放在receiveStr里面,然后就可以用函数xmlParseMemory 来解析出Document 了,

pdoc = xmlParseMemory(receiveStr, strlen(receiveStr));

然后就可以从Document 里找出Root Element,使用函数是xmlDocGetRootElement

root = xmlDocGetRootElement(pdoc);

然后就去解析下面的节点(注意每一步都应该判断一下是否为空,因为可能因为数据问题导致解析失败)

information = findNodeByName(root, "information");

这个函数是自己写的,貌似在libxml2里没有提供类似这样直接查找的函数,只能一个一个节点看,比较麻烦,所以就抽了出来放在一个函数里面了。

xmlNodePtr findNodeByName(xmlNodePtr parent, char * nodeName){xmlNodePtr temp;if(parent==NULL){printf("empty parent node \n");return NULL;}for(temp = parent->children; temp!=NULL; temp = temp->next){//printf("searching name is ---> %s\n",temp->name);if(strcmp(temp->name, nodeName)==0)return temp;}return NULL;}

这个函数只适用于这次这种简单的情况,因为这次一个Element下所有的节点都不会有重名的情况出现,所以就比较查找出第一个就是那唯一的一个了,不需要考虑多个的情况。

先要看看xmlNodePtr是什么,

Typedef xmlNode * xmlNodePtr

这个就是一个xmlNode的指针,然后再看一下xmlNode

Structure xmlNodestruct _xmlNode {    void *_private: application data    xmlElementTypetype: type number, must be second !    const xmlChar *name: the name of the node, or the entity    struct _xmlNode *children: parent->childs link    struct _xmlNode *last: last child link    struct _xmlNode *parent: child->parent link    struct _xmlNode *next: next sibling link    struct _xmlNode *prev: previous sibling link    struct _xmlDoc *doc: the containing document End of common p    xmlNs *ns: pointer to the associated namespace    xmlChar *content: the content    struct _xmlAttr *properties: properties list    xmlNs *nsDef: namespace definitions on this node    void *psvi: for type/PSVI informations    unsigned shortline: line number    unsigned shortextra: extra data for XPath/XSLT}

这里面有children 指针和next 指针,笔者主要就是用到这两个指针。通过children 来找到第一个子节点,然后再根据next 来逐个查找,找到了就返回这个指针,这就是这个findNodeByName 的过程了。

找到需要的节点后使用xmlNodeGetContent 来获取节点下的内容,笔者这里就根据之前订好的协议来解析响应了。

首先是通过information 节点下的code 节点来看响应类型,再根据响应的不同来给出不同的输出:

// 如果找到了code节点if(strcmp(xmlNodeGetContent(code),"200")==0){// 如果code节点内容为200messages = findNodeByName(root, "messages");outputMessages(messages);returnCode = 200;}else if(strcmp(xmlNodeGetContent(code), "201")==0){// 如果code节点内容为201room = findNodeByName(root, "roomname");detail = findNodeByName(information, "detail");messages = findNodeByName(root, "messages");printf("------------------\n");printf("%s\n\n", room!=NULL?xmlNodeGetContent(room):"unknown room name");outputDetail(detail);printf("------------------\n\n");outputMessages(messages);returnCode = 201;}else if(strcmp(xmlNodeGetContent(code), "500")==0){// 如果code节点内容为500, 服务器异常printf("server error, please try again later\n");returnCode = 500;}else if(strcmp(xmlNodeGetContent(code), "400")==0){// 如果code节点内容为400, 用户已失效printf("time out, please login once more\n");returnCode = 400;}else if(strcmp(xmlNodeGetContent(code), "404")==0){// 如果code节点内容为404, 用户不在房间中printf("you are out of chat room, please find a new one\n");returnCode = 404;}else{printf("can't find conventional status code\n");returnCode = -1;}xmlFreeDoc(pdoc);return returnCode;

最后有个xmlFreeDoc 这个是释放资源的函数,最后记得要调用。另外在前面如果发现某个节点为空需要直接return 的时候也要调用这个函数进行释放。

其中还调用了两个函数,就是专门拿来输出的,下面直接附上其中一个吧,其实就是根据协议来一条条解析,没什么特别的,另一个是类似的

int outputMessages(xmlNodePtr messages){xmlNodePtr message;xmlNodePtr time, name, content;if(messages == NULL){printf("empty messages node\n");return -1;}for(message = messages->children; message != NULL; message = message->next){time = findNodeByName(message, "time");name = findNodeByName(message, "name");content = findNodeByName(message, "content");printf("%s", name!=NULL?xmlNodeGetContent(name):"unknown talker");printf("(");printf("%s", time!=NULL?xmlNodeGetContent(time):"unknown time");printf("):\n");printf("%s\n\n", content!=NULL?xmlNodeGetContent(content):"");}strcpy(_time, xmlNodeGetContent(time));return 0;}

————————————–

这次就先到这吧…

不要害怕错过什么,因为在路上你就已经收获了自由自在的好心情。

基于Linux C的聊天室客户端(二)libxml2的使用

相关文章:

你感兴趣的文章:

标签云: