由于项目需要,这两天在用C++做XML文件解析的工作。在linux下有个很方便的操作xml文件的库——libxml2,它提供了一套创建和查询xml文件的C语言的接口。这篇博客主要介绍如何使用libxml2读取并解析xml文件。
下载并安装libxml2
下载地址:ftp://xmlsoft.org/libxml2/
下载最新的版本,我下载的是libxml2-2.9.1.tar.gz。下载后将文件解压到合适的位置,进入解压后的目录。
编译命令非常简单(注意:如果configure文件没有可执行权限,增加可执行权限):
./configure
make
make install
此时libxml2相关的头文件应该在/usr/local/include/libxml2目录下,libxml2相关的库文件应该在/usr/local/lib目录下。
解析XML文档的两种方式
在使用libxml2进行XML文档的解析时,非常推荐使用XPath语言实现,如果把XML文件看作数据库的话,那么XPath就可被视为sql,我们只要构造一定格式的语句就可查询到相关结果,而在在libxml2中使用Xpath是非常简单的。当然我们也可以直接通过libxml2相关接口从跟节点出发,根据整个xml的父子节点关系定位到相关节点进行查询。下面我将分别对这两种方式进行介绍。
我们使用下面的xml测试用例:
<?xml version="1.0" encoding="ISO-8859-1"?> <bookstore> <book> <title lang="eng">Harry Potter</title> <price>29.99</price> </book> <book> <title lang="eng">Learning XML</title> <price>39.95</price> </book> </bookstore>
直接使用libxml2接口解析XML文档
#include <stdio.h> #include <stdlib.h> #include <libxml/parser.h> #include <libxml/tree.h> int main (int argc , char **argv) { xmlDocPtr pdoc = NULL; xmlNodePtr proot = NULL, pcur = NULL; /*****************打开xml文档********************/ xmlKeepBlanksDefault(0);//必须加上,防止程序把元素前后的空白文本符号当作一个node pdoc = xmlReadFile ("test.xml", "UTF-8", XML_PARSE_RECOVER);//libxml只能解析UTF-8格式数据 if (pdoc == NULL) { printf ("error:can't open file! "); exit (1); } /*****************获取xml文档对象的根节对象********************/ proot = xmlDocGetRootElement (pdoc); if (proot == NULL) { printf("error: file is empty! "); exit (1); } /*****************查找书店中所有书籍的名称********************/ pcur = proot->xmlChildrenNode; while (pcur != NULL) { //如同标准C中的char类型一样,xmlChar也有动态内存分配,字符串操作等 相关函数。例如xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字符串比较函数等。 //对于char* ch="book", xmlChar* xch=BAD_CAST(ch)或者xmlChar* xch=(const xmlChar *)(ch) //对于xmlChar* xch=BAD_CAST("book"),char* ch=(char *)(xch) if (!xmlStrcmp(pcur->name, BAD_CAST("book"))) { xmlNodePtr nptr=pcur->xmlChildrenNode; while (pcur != NULL) { if (!xmlStrcmp(nptr->name, BAD_CAST("title"))) { printf("title: %s ",((char*)XML_GET_CONTENT(nptr->xmlChildrenNode))); break; } } } pcur = pcur->next; } /*****************释放资源********************/ xmlFreeDoc (pdoc); xmlCleanupParser (); xmlMemoryDump (); return 0; }
具体流程我已经在代码中详细注释,这里就不单独拿出来解释。
使用XPath语言解析XML文档
#include <stdio.h> #include <stdlib.h> #include <libxml/parser.h> #include <libxml/tree.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/xmlmemory.h> #include <libxml/xpointer.h> xmlXPathObjectPtr getNodeset(xmlDocPtr pdoc,const xmlChar *xpath) { xmlXPathContextPtr context=NULL;//XPath上下文指针 xmlXPathObjectPtr result=NULL; //XPath结果指针 context = xmlXPathNewContext(pdoc); if(pdoc==NULL){ printf("pdoc is NULL "); return NULL; } if(xpath){ if (context == NULL) { printf("context is NULL "); return NULL; } result = xmlXPathEvalExpression(xpath, context); xmlXPathFreeContext(context); //释放上下文指针 if (result == NULL) { printf("xmlXPathEvalExpression return NULL "); return NULL; } if (xmlXPathNodeSetIsEmpty(result->nodesetval)) { xmlXPathFreeObject(result); printf("nodeset is empty "); return NULL; } } return result; } int main (int argc , char **argv){ xmlDocPtr pdoc = NULL; xmlNodePtr proot = NULL; /*****************打开xml文档********************/ xmlKeepBlanksDefault(0);//必须加上,防止程序把元素前后的空白文本符号当作一个node pdoc = xmlReadFile ("test.xml", "UTF-8", XML_PARSE_RECOVER);//libxml只能解析UTF-8格式数据 if (pdoc == NULL) { printf ("error:can't open file! "); exit (1); } /*****************获取xml文档对象的根节对象********************/ proot = xmlDocGetRootElement (pdoc); if (proot == NULL) { printf("error: file is empty! "); exit (1); } /*****************查找书店中所有书籍的名称********************/ xmlChar *xpath = BAD_CAST("//book"); //xpath语句 xmlXPathObjectPtr result = getNodeset(pdoc, xpath); //查询XPath表达式,得到一个查询结果 if (result == NULL) { printf("result is NULL "); exit (1); } if(result) { xmlNodeSetPtr nodeset = result->nodesetval; //获取查询到的节点指针集合 xmlNodePtr cur; //nodeset->nodeNr是集合元素总数 for (int i=0; i < nodeset->nodeNr; i++) { cur = nodeset->nodeTab[i]; cur = cur->xmlChildrenNode; while (cur != NULL) { //如同标准C中的char类型一样,xmlChar也有动态内存分配,字符串操作等 相关函数。例如xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字符串比较函数等。 //对于char* ch="book", xmlChar* xch=BAD_CAST(ch)或者xmlChar* xch=(const xmlChar *)(ch) //对于xmlChar* xch=BAD_CAST("book"),char* ch=(char *)(xch) if (!xmlStrcmp(cur->name, BAD_CAST("title"))) { printf("title: %s ",((char*)XML_GET_CONTENT(cur->xmlChildrenNode))); break; } cur = cur->next; } } xmlXPathFreeObject(result);//释放结果指针 } /*****************释放资源********************/ xmlFreeDoc (pdoc); xmlCleanupParser (); xmlMemoryDump (); return 0; }
具体流程我已经在代码中详细注释,这里就不单独拿出来解释。
更加详细的libxml2接口,可以访问http://xmlsoft.org/html/libxml-tree.html
编译程序并运行
编译上述程序
g++ search1.cpp -I/usr/local/include/libxml2 -L/usr/local/lib -lxml2 -o search1
g++ search2.cpp -I/usr/local/include/libxml2 -L/usr/local/lib -lxml2 -o search2
运行程序及运行结果
运行./search1
显示如下结果:
title: Harry Potter
title: Learning XML
运行./search2
显示如下结果:
title: Harry Potter
title: Learning XML
来自:http://blog.csdn.net/l_h2010/article/details/38639143