由於項目需要,這兩天在用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!\n"); exit (1); } /*****************獲取xml文檔對象的根節對象********************/ proot = xmlDocGetRootElement (pdoc); if (proot == NULL) { printf("error: file is empty!\n"); 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\n",((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\n"); return NULL; } if(xpath){ if (context == NULL) { printf("context is NULL\n"); return NULL; } result = xmlXPathEvalExpression(xpath, context); xmlXPathFreeContext(context); //釋放上下文指針 if (result == NULL) { printf("xmlXPathEvalExpression return NULL\n"); return NULL; } if (xmlXPathNodeSetIsEmpty(result->nodesetval)) { xmlXPathFreeObject(result); printf("nodeset is empty\n"); 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!\n"); exit (1); } /*****************獲取xml文檔對象的根節對象********************/ proot = xmlDocGetRootElement (pdoc); if (proot == NULL) { printf("error: file is empty!\n"); exit (1); } /*****************查找書店中所有書籍的名稱********************/ xmlChar *xpath = BAD_CAST("//book"); //xpath語句 xmlXPathObjectPtr result = getNodeset(pdoc, xpath); //查詢XPath表達式,得到一個查詢結果 if (result == NULL) { printf("result is NULL\n"); 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\n",((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