Libxml2 是一個xml c語言版的解析器,本來是為Gnome項目開發(fā)的工具,是一個基于MIT License的免費開源軟件。它除了支持c語言版以外,還支持c++、PHP、Pascal、Ruby、Tcl等語言的綁定,能在Windows、Linux、Solaris、MacOsX等平臺上運行。功能還是相當(dāng)強大的,相信滿足一般用戶需求沒有任何問題。 本文主要簡單介紹一下libxml2在linux下的C++使用的基礎(chǔ),操作系統(tǒng)為Ubuntu。
一、libxml2的安裝
1、下載libxml2
地址ftp://xmlsoft.org/libxml2/,這里選擇的是libxml2-2.8.0.tar.gz
2、解壓
- tar zxvf libxml2-2.8.0.tar.gz
3、配置安裝
- ./configure
- make
- sudo make install
4、安裝libxml-dev
- sudo apt-get install libxml2-dev
5、把libxml2下的libxml拷貝一份到libxml2所在的目錄
- sudo cp -r /usr/include/libxml2/libxml /usr/include/libxml
6、包含libxml2的測試程序在編譯的時候需要引用xml2庫,比如測試程序test.cpp,則在編譯的時候應(yīng)該:
二、libxml2常用數(shù)據(jù)類型
xmlChar是libxml2中的字符類型,在庫中的所有字符,字符串都是基于這個數(shù)據(jù)類型的。
xmlChar*是指針類型,很多函數(shù)都會返回一個動態(tài)分配的內(nèi)存的xmlChar*類型的變量,因此,在使用這類函數(shù)時要記得釋放內(nèi)存,否則會導(dǎo)致內(nèi)存泄漏,例如這樣的用法:
- xmlChar *name = xmlNodeGetContent(CurNode);
- strcpy(data.name, name);
- xmlFree(name);
xmlDoc
、 xmlDocPtr
//文檔對象結(jié)構(gòu)體及指針 xmlNode、 xmlNodePtr //節(jié)點對象結(jié)構(gòu)體及節(jié)點指針
xmlAttr、 xmlAttrPtr //節(jié)點屬性的結(jié)構(gòu)體及其指針
xmlNs、 xmlNsPtr //節(jié)點命名空間的結(jié)構(gòu)及指針
BAD_CAST //一個宏定義,事實上它即是xmlChar*類型
三、libxml2常用函數(shù)
int xmlKeepBlankDefault(int val); //設(shè)置是否忽略空白的節(jié)點,在解析之前一般要調(diào)用,默認(rèn)值為0,最好設(shè)置成為1
xmlDocPtr xmlParseFile(const *filename); //分析一個xml文件,并返回一個xml文檔的對象指針
xmlReadFile //讀入一個帶有某種編碼的xml文檔,并返回一個文檔指針
xmlSaveFile //將文檔以默認(rèn)方式保存
xmlSaveFormatFileEnc //可將文檔以某種編碼/格式的方式進(jìn)行保存
xmlFreeDoc //釋放文檔指針 注意:當(dāng)調(diào)用此函數(shù)時,該文檔所包含的所有節(jié)點內(nèi)存都將被自動釋放。一般來說,一個文檔中所有的節(jié)點都應(yīng)該動態(tài)分配然后加入文檔,然后調(diào)用xmlFreeDoc函數(shù)一次性的釋放所有節(jié)點動態(tài)分配的內(nèi)存;但是當(dāng)節(jié)點從文檔中移除時,就需要調(diào)用xmlFreeNode或者是xmlFreeNodeList。
2、根節(jié)點相關(guān)函數(shù)
xmlNodePtr xmlDocGetRootElement(xmlDocPtr doc); //獲得文檔的根節(jié)點
xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root); //設(shè)置文檔的根節(jié)點
3、創(chuàng)建子節(jié)點相關(guān)函數(shù)
xmlNodePtr xmlNewNode(xmlNsPtr ns, const xmlChar *name); //創(chuàng)建一個新節(jié)點
xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); // 創(chuàng)建一個新的字節(jié)點
xmlNodePtr xmlCopyNode(const xmlNodePtr curNode, int extended); //復(fù)制當(dāng)前節(jié)點
xmlNodeSetContent //設(shè)置節(jié)點內(nèi)容
xmlNodeGetContent //獲取節(jié)點內(nèi)容
xmlNodeListGetString //獲取字符串
4、添加字節(jié)點相關(guān)函數(shù)
xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr curNode); //給指定的節(jié)點添加子節(jié)點
xmlNodePtr xmlAddNextSibling(xmlNodePtr curNode, xmlNodePtr brother); //添加兄弟節(jié)點到后面
xmlNodePtr xmlAddPrevSibling(xmlNodePtr curNode, xmlNodePtr brother); //添加兄弟節(jié)點到前面
xmlNodePtr xmlAddSibling(xmlNodePtr curNode, xmlNodePtr brother); //添加一個兄弟節(jié)點
5、屬性相關(guān)函數(shù)
xmlAttrPtr xmlNewProp(xmlNodePtr curNode, const xmlChar *name, const xmlChar *value);//創(chuàng)建新節(jié)點屬性
xmlAttrPtr xmlSetProp(xmlNodePtr curNode, const xmlChar *name, const xmlChar *value);//設(shè)置新節(jié)點屬性
xmlAttrPtr *xmlGetProp(xmlNodePtr curNode, const xmlChar *name, const xmlChar *value);//讀取節(jié)點屬性
6、使用XPATH查找xml文檔
使用XPATH的流程如下:
1、定義一個XPATH的上下文指針xmlXPathContextPtr context,并且使用函數(shù)xmlXPathNewContext來初始化該指針;
2、定義一個XPATH的對象指針xmlXPathObjectPtr obj,并使用函數(shù)xmlXPathEvalExpression來計算XPATH的表達(dá)式,得到查詢結(jié)果,將結(jié)果存入對象指針當(dāng)中;
3、使用obj->nodesetval得到節(jié)點集合指針,在其中包含了所有查詢到的XPATH節(jié)點;
4、使用函數(shù)xmlXPathFreeContext來釋放上下文指針;
5、最后使用函數(shù)xmlXPathFreeObject釋放XPATH對象指針。
四、XML文件創(chuàng)建
- #include<iostream>
- #include<libxml/parser.h>
- #include<libxml/xpath.h>
- #include<libxml/tree.h>
-
- using namespace std;
-
- int main(){
- xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");
- xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root");
- //set root node
- xmlDocSetRootElement(doc,root_node);
- //create nodes under root node
- xmlNewTextChild(root_node,NULL,BAD_CAST"IP",BAD_CAST"192.168.1.116");
- xmlNewTextChild(root_node,NULL,BAD_CAST"Port",BAD_CAST"65535");
- xmlNewTextChild(root_node,NULL,BAD_CAST"num",BAD_CAST"1000");
- //create a new node,set its content and attributes,then add it to root node
- xmlNodePtr node = xmlNewNode(NULL,BAD_CAST"node2");
- xmlNodePtr content = xmlNewText(BAD_CAST"NODE CONTENT");
- //add node to root node
- xmlAddChild(root_node,node);
- xmlAddChild(node,content);
- xmlNewProp(node,BAD_CAST"attribute",BAD_CAST"yes");
- //create a son node and a grandson one
- node = xmlNewNode(NULL,BAD_CAST"son");
- xmlAddChild(root_node,node);
- xmlNodePtr grandson = xmlNewNode(NULL,BAD_CAST"grandson");
- xmlAddChild(node,grandson);
- xmlAddChild(grandson,xmlNewText(BAD_CAST"This is a grandson node"));
- //save xml doc
- int ret = xmlSaveFile("create.xml",doc);
- if(ret != -1){
- cout<<"A xml doc is created;Write in "<<ret<<" bytes"<<endl;
- }
- xmlFreeDoc(doc);
- return 0;
- }
編譯:g++ build.cc -lxml2
運行:打開create.xml
- <?xml version="1.0"?>
- <root>
- <IP>192.168.1.116</IP>
- <Port>65535</Port>
- <num>1000</num>
- <node2 attribute="yes">NODE CONTENT</node2>
- <son>
- <grandson>This is a grandson node</grandson>
- <son>
- </root>
五、XML文件解析
xml文件
- <?xml version="1.0"?>
- <root>
- <IP>192.168.1.116</IP>
- <Port>65535</Port>
- <num>1000</num>
- <node2 attribute="yes">NODE CONTENT</node2>
- <son>
- <grandson>This is a grandson node</grandson>
- <son>
- </root>
解析代碼:
- #include<iostream>
- #include<libxml/parser.h>
- //#include<libxml/xmlmemory.h>
- #include<string>
-
- using namespace std;
-
- const char* xmlConfig="create.xml";
-
- int main(){
- xmlDocPtr doc;
- xmlNodePtr curNode;
- xmlChar* szKey;
-
- doc = xmlParseFile(xmlConfig);
- if(doc == NULL){
- cout<<"Document not parsed successfully!"<<endl;
- return -1;
- }
- //cout<<"Document parsed successfully!"<<endl;
- curNode = xmlDocGetRootElement(doc);
- if(curNode == NULL){
- cout<<"empty document.\n"<<endl;
- xmlFreeDoc(doc);
- return -1;
- }
- //cout<<"xmlDocGetRootElement OK.\n"<<endl;
- if(xmlStrcmp(curNode->name,BAD_CAST"root")){
- cerr<<"root node is not 'root'"<<endl;
- xmlFreeDoc(doc);
- return -1;
- }
- curNode = curNode->xmlChildrenNode;
- xmlNodePtr propNodePtr = curNode;
- while(NULL != curNode){
- if((!xmlStrcmp(curNode->name,(const xmlChar*)"IP"))){
- szKey = xmlNodeGetContent(curNode);
- cout<<"IP:"<<szKey<<endl;
- //string s((char*)szKey);
- xmlFree(szKey);
- //cout<<s<<endl;
- }else if((!xmlStrcmp(curNode->name,(const xmlChar*)"Port"))){
- szKey = xmlNodeGetContent(curNode);
- cout<<"Port:"<<szKey<<endl;
- xmlFree(szKey);
- }else if((!xmlStrcmp(curNode->name,(const xmlChar*)"num"))){
- szKey = xmlNodeGetContent(curNode);
- cout<<"num:"<<szKey<<endl;
- xmlFree(szKey);
- } else if((!xmlStrcmp(curNode->name,(const xmlChar*)"node2"))){
- szKey = xmlNodeGetContent(curNode);
- cout<<"node2:"<<szKey<<endl;
- xmlFree(szKey);
- // get attributes
- szKey = xmlGetProp(curNode,(const xmlChar*)"attribute");
- cout<<"node2->attribute:"<<szKey<<endl;
- xmlFree(szKey);
- }
- curNode= curNode->next;
- }
-
- return 0;
- }