原文轉自 http://blog.csdn.net/K346K346/article/details/48750417
1.TinyXML2概述
TinyXML2是simple、small、efficient開源的C++ XML文件解析庫,可以很方便的應用到現有的項目之中。非常適合存儲簡單數據,配置文件,對象序列化等數據量不是很大的操作。
TinyXML2詳細介紹與源碼獲取方法詳見:TinyXML2官網。
2. TinyXML1與TinyXML2對比
TinyXML1與TinyXML2這兩個著名的開源XML文件解析庫均出自Lee Thomason之手,向這位滿懷開源精神的大家致敬。
TinyXML2適用於大部分的C/C++項目開發,經得住考驗,是最好的選擇。較TinyXML1而言,TinyXML2化繁為簡,使用時只需要包含兩個文件,而TinyXML1需要6個文件,一般生成靜態鏈接庫供項目的使用。TinyXML1詳細介紹與源碼見:TinyXML1官網。TinyXML1用法用例可以參考博文:TinyXML快速入門。
TinyXML2使用了與TinyXML1相似都可API,並且擁有豐富的測試案例。但TinyXML2解析器相對TinyXML1在代碼上是完全重寫,使其更適合於游戲開發中使用。它使用更少的內存,更快,並使用更少的內存分配。
TinyXML2無需STL,也放棄了對STL支持。所有字符串查詢均使用C風格字符串“const char *”來表示,省去string類型對象的構造,並使代碼更簡單。
二者共同點: (1)都使用了簡單易用的API。 (2)都是基於DOM(Document Object Model,文檔對象模型)的解析器。 (3)都支持UTF-8編碼。
TinyXML2的優點: (1)對大部分大部分的C/C++項目具有普適性。 (2)使用較少的內存(約TinyXML1的40%),速度變得更快。 (3)沒有C++的STL的要求。 (4)更接近現代C++的特性,如使用了適當的命名空間。 (5)適當有效的處理了的空白字符(空格,TAB和回車)。
TinyXML1的優點: (1)可以報告分析錯誤的位置。 (2)提供一些C++ STL公約支持:流和字符串。 (3)擁有非常成熟和良好的調試代碼庫。
3. TinyXML2的用法用例
TinyXML2的網上教程並不多見,醍醐灌頂,受益匪淺的教程更是鳳毛麟角。有的也是蜻蜓點水、參差不齊的泛泛而談。最終,所能參考的資料也就是官網的文檔和示例代碼,但卻有點晦澀難懂。因此,本文就為了解決這個尷尬的局面,結合官網的資料和網上資源,盡量詳細的列出TinyXML2的常見用法用例,不足之處,請留言補充,后續增加修改。
xml文件本質就是小型的數據庫,換個角度來說就是,對數據庫有什么操作,那么對xml文件就應能實現什么操作。一般而言,對數據庫的操作包括以下幾種:新建數據庫和對數據庫增刪查改。那么對應xml文件就是新建xml文件、增加xml文件的節點,刪除xml文件的指定節點,查詢xml文件指定節點的值,修改xml文件中節點的值。
使用方法:將tinyxml2.cpp和tinyxml2.h拷貝至項目目錄,使用時包含#include “tinyxml2.h”和using namespace tinyxml2。
使用場景:存儲用戶信息。
用戶數據表設計如下:
變量名 | 描述 | 類型 | 長度(字節) | 不為空 | 主鍵 |
---|---|---|---|---|---|
UserName | 用戶名 | Vchar | 3-20 | Y | Y |
Password | 密碼 | Char | 32 | Y | N |
Gender | 性別 | Int | 1 | N | N |
Mobile | 電話 | Char | 11 | N | N |
電子郵箱 | Varchar | 1-50 | N | N |
對應XML文件實現如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <DBUSER> <User Name=”lvlv” Password =”123456”> <Gender></Gender> <Mobile ></ Mobile> <Email ></ Email > </User> . . . <DBUSER>
從中可以看出,XML由三大部分組成,分別是聲明、根節點和其它節點。其中xml文件的聲明包括三方面的內容:Version、Standalone和Encoding。下面將詳細列出常見tinyxml2的用法。
注意:以下示例代碼針對本人下載使用的TinyXML2,官網的TinyXML2在不斷的完善和更新當中,最新的TinyXML2和本人的示例代碼可能會有出入。本人使用的TinyXML2是2015.9.23從官網下載的,已上傳至CSDN下載,見:TinyXML2。
3.1創建XML文件
示例代碼:
//function:create a xml file //param:xmlPath:xml文件路徑 //return:0,成功,非0,失敗 int createXML(const char* xmlPath) { const char* declaration ="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"; XMLDocument doc; doc.Parse(declaration);//會覆蓋xml所有內容 //添加申明可以使用如下兩行 //XMLDeclaration* declaration=doc.NewDeclaration(); //doc.InsertFirstChild(declaration); XMLElement* root=doc.NewElement("DBUSER"); doc.InsertEndChild(root); return doc.SaveFile(xmlPath); }
創建結果:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <DBUSER/>
3.2增加xml文件的節點
示例代碼:
//用戶類 class User { public: User(){ gender=0; }; User(const string& userName, const string& password, int gender, const string& mobile, const string& email){ this->userName=userName; this->password=password; this->gender=gender; this->mobile=mobile; this->email=email; }; string userName; string password; int gender; string mobile; string email; }; //function:insert XML node //param:xmlPath:xml文件路徑; user:用戶對象 //return:0:成功; 非0:失敗 int insertXMLNode(const char* xmlPath,const User& user) { XMLDocument doc; int res=doc.LoadFile(xmlPath); if(res!=0) { cout<<"load xml file failed"<<endl; return res; } XMLElement* root=doc.RootElement(); XMLElement* userNode = doc.NewElement("User"); userNode->SetAttribute("Name",user.userName.c_str()); userNode->SetAttribute("Password ",user.password.c_str()); root->InsertEndChild(userNode); XMLElement* gender = doc.NewElement("Gender"); XMLText* genderText=doc.NewText(itoa(user.gender)); gender->InsertEndChild(genderText); userNode->InsertEndChild(gender); XMLElement* mobile = doc.NewElement("Mobile"); mobile->InsertEndChild(doc.NewText(user.mobile.c_str())); userNode->InsertEndChild(mobile); XMLElement* email = doc.NewElement("Email"); email->InsertEndChild(doc.NewText(user.email.c_str())); userNode->InsertEndChild(email); return doc.SaveFile(xmlPath); }
創建結果:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <DBUSER> <User Name="lvlv" Password ="12346"> <Gender>1</Gender> <Mobile>15813354926</Mobile> <Email>1589276509@qq.com</Email> </User> </DBUSER>
3.3查詢xml文件的指定節點
Xml文件中,一個用戶節點存儲一個用戶的信息。因此,對用戶信息的增刪查改,即無論查詢節點、刪除節點、修改節點和增加節點,都需要獲取需要操作的節點。那么先實現一個根據用戶名獲取節點指針的函數:
//function:根據用戶名獲取用戶節點 //param:root:xml文件根節點;userName:用戶名 //return:用戶節點 XMLElement* queryUserNodeByName(XMLElement* root,const string& userName) { XMLElement* userNode=root->FirstChildElement("User"); while(userNode!=NULL) { if(userNode->Attribute("Name")==userName) break; userNode=userNode->NextSiblingElement();//下一個兄弟節點 } return userNode; }
在以上函數的基礎上,獲取用戶信息的函數:
User* queryUserByName(const char* xmlPath,const string& userName) { XMLDocument doc; if(doc.LoadFile(xmlPath)!=0) { cout<<"load xml file failed"<<endl; return NULL; } XMLElement* root=doc.RootElement(); XMLElement* userNode=queryUserNodeByName(root,userName); if(userNode!=NULL) //searched successfully { User* user=new User(); user->userName=userName; user->password=userNode->Attribute("Password"); XMLElement* genderNode=userNode->FirstChildElement("Gender"); user->gender=atoi(genderNode->GetText()); XMLElement* mobileNode=userNode->FirstChildElement("Mobile"); user->mobile=mobileNode->GetText(); XMLElement* emailNode=userNode->FirstChildElement("Email"); user->email=emailNode->GetText(); return user; } return NULL; }
3.4修改xml文件的指定節點
//function:修改指定節點內容 //param:xmlPath:xml文件路徑;user:用戶對象 //return:bool bool updateUser(const char* xmlPath,User* user) { XMLDocument doc; if(doc.LoadFile(xmlPath)!=0) { cout<<"load xml file failed"<<endl; return false; } XMLElement* root=doc.RootElement(); XMLElement* userNode=queryUserNodeByName(root,user->userName); if(userNode!=NULL) { if(user->password!=userNode->Attribute("Password")) { userNode->SetAttribute("Password",user->password.c_str()); //修改屬性 } XMLElement* genderNode=userNode->FirstChildElement("Gender"); if(user->gender!=atoi(genderNode->GetText())) { genderNode->SetText(itoa(user->gender).c_str()); //修改節點內容 } XMLElement* mobileNode=userNode->FirstChildElement("Mobile"); if(user->mobile!=mobileNode->GetText()) { mobileNode->SetText(user->mobile.c_str()); } XMLElement* emailNode=userNode->FirstChildElement("Email"); if(user->email!=emailNode->GetText()) { emailNode->SetText(user->email.c_str()); } if(doc.SaveFile(xmlPath)==0) return true; } return false; }
驗證代碼:
int main(int argc,char* argv[]) { //修改用戶信息 User user("lvlv","00001111",0,"13995648666","1586666@qq.com"); if(updateUser("./user.xml",&user)) cout<<"update successfully"<<endl; else cout<<"update failed"<<endl; return 0; }
修改結果:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <DBUSER> <User Name="lvlv" Password="00001111"> <Gender>0</Gender> <Mobile>13995648666</Mobile> <Email>1586666@qq.com</Email> </User> </DBUSER>
3.5刪除xml文件的指定節點的信息
//function:刪除指定節點內容 //param:xmlPath:xml文件路徑;userName:用戶名稱 //return:bool bool deleteUserByName(const char* xmlPath,const string& userName) { XMLDocument doc; if(doc.LoadFile(xmlPath)!=0) { cout<<"load xml file failed"<<endl; return false; } XMLElement* root=doc.RootElement(); //doc.DeleteNode(root);//刪除xml所有節點 XMLElement* userNode=queryUserNodeByName(root,userName); if(userNode!=NULL) { userNode->DeleteAttribute("Password");//刪除屬性 XMLElement* emailNode=userNode->FirstChildElement("Email"); userNode->DeleteChild(emailNode); //刪除指定節點 //userNode->DeleteChildren();//刪除節點的所有孩子節點 if(doc.SaveFile(xmlPath)==0) return true; } return false; }
驗證代碼:
int main(int argc,char* argv[]) { //刪除用戶某些信息 if(deleteUserByName("./user.xml","lvlv")) cout<<"delete successfully"<<endl; else cout<<"delete failed"<<endl; return 0; }
刪除結果:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <DBUSER> <User Name="lvlv"> <Gender>10</Gender> <Mobile>13995648666</Mobile> </User> </DBUSER>
4.其它常見用例
4.1獲取xml文件申明
//function:獲取xml文件申明 //param:xmlPath:xml文件路徑;strDecl:xml申明 //return:bool bool getXMLDeclaration(const char* xmlPath,string& strDecl) { XMLDocument doc; if(doc.LoadFile(xmlPath)!=0) { cout<<"load xml file failed"<<endl; return false; } XMLNode* decl=doc.FirstChild(); if (NULL!=decl) { XMLDeclaration* declaration =decl->ToDeclaration(); if (NULL!=declaration) { strDecl = declaration->Value(); return true; } } return false; }
驗證代碼:
int main(int argc,char* argv[]) { //獲取xml文件申明 string strDecl; if(getXMLDeclaration("./user.xml",strDecl)) { cout<<"declaration:"<<strDecl<<endl; } return 0; }
驗證結果:
declaration:xml version="1.0" encoding="UTF-8" standalone="no"
4.2打印xml文件至標准輸出
//function:將xml文件內容輸出到標准輸出 //param:xmlPath:xml文件路徑 void print(const char* xmlPath) { XMLDocument doc; if(doc.LoadFile("./user.xml")!=0) { cout<<"load xml file failed"<<endl; return; } doc.Print(); }
4.3 xml文件內容輸出至內存
XMLPrinter printer;
doc.Print( &printer ); // printer.CStr() has a const char* to the XML
4.4如何解析xml格式的字符串信息,不是文件中的
采用tinyXML中的TiXmlDocument類的Parse方法即可。例如:
const char * xmlString = "<?xml version=\"1.0\" standalone=no>\n<!– Our to do list data –>\n<ToDo>\n<Item priority=\"1\"> <bold>Toy store!</bold>\n</Item>\n<Item priority=\"2\"> Do bills</Item>\n</ToDo> ";
XMLDocument *doc = new XMLDocument();
doc->Parse(xmlString);
XMLElement * rootElement = doc->RootElement();
const char * rootName = rootElement->Value();