一、TinyXml2庫概述
- TinyXML2 是簡單實用的開源的 C++XML 文件解析庫,可以很方便的應用到現有的項目之中。TinyXML2 解析器相對 TinyXML1 在代碼上是完全重寫,使其更適合於遊戲開發中使用。它使用更少的內存,更快,並使用更少的內存分配
庫的安裝
- 通過下面進行下載:
git clone https://github.com/leethomason/tinyxml2.git
- 下載完成之後進入目錄進行編碼
cd tinyxml2/ make
- 編譯完成之後執行下面的可執行程序是否編譯成功
./xmltest
- 編譯成功之後進行安裝
sudo make install
- 默認情況下,TinyXml2庫的頭文件安裝在/usr/local/include/目錄下,動態庫文件安裝在/usr/local/lib/目錄下
編譯帶有TinyXml2庫的C++程序
- 有兩種方式:
- ①方式一:像上面一樣,將TinyXml2庫安裝,然後將TinyXml2庫源碼目錄下的tinyxml2.cpp同時拷貝到自己的項目目錄下
- ②方式二:不用像上面一樣安裝TinyXml2庫,直接將TinyXml2庫源碼目錄下的tinyxml2.h和tinyxml2.c文件拷貝到項目下就可以編譯使用了
- 編譯程序時使用下面的命令:
g++ tinyxml2.cpp demo.cpp -o demo -std=c++11
二、節點、元素、屬性、值的關係
- 由於 XML 的樹狀結構,TinyXML2 將:
- XML 的節點抽象爲 XMLNode
- XML 中除了把屬性 key-value 抽象爲 XMLAttribute 類型外,其餘的都看作 XMLNode 的子類
- 首先將整個 XML 文檔抽象爲 XMLDocument
- 將聲明部分抽象爲 XMLDeclaration
- 將註釋抽象爲 XMLComment
- 將元素抽象爲 XMLElement
- 將文本抽象爲 XMLText
- xml在內存中存儲時有兩種方式:
- 將xml以dom(Document Object Model)樹的結構加載到內存中,是一種樹形結構。當xml內容比較多時佔用內存大
- SAX(Sample API for XML)事件驅動讀取xml的時候逐行解析xml,一邊掃描一邊解析
三、API的用法
加載XML的兩種方法
- 方式一:從本地文件中讀取
tinyxml2::XMLDocument doc; doc.LoadFile( "test.xml" ); std::cout << doc.ErrorID() << std::endl;
- 方式二:從內存中加載XML
static const char* xml = "<element/>"; tinyxml2::XMLDocument doc; doc.Parse( xml ); std::cout << doc.ErrorID() << std::endl;
待續
四、演示案例1
- 下面的demo01.cpp演示從本地讀取文件demo01.xml然後加載到內存中
- Github鏈接:https://github.com/dongyusheng/csdn-code/tree/master/tinyxml2
代碼實現
//demo01.cpp //讀取本地的文件加載到內存 #include <iostream> #include "tinyxml2.h" int main(void) { tinyxml2::XMLDocument doc; // 本地文件讀取 tinyxml2::XMLError ret = doc.LoadFile("demo01.xml"); std::cout << doc.ErrorID() << std::endl; std::cout << ret << std::endl; // 加載到內存 tinyxml2::XMLPrinter printer; doc.Print(&printer); // 打印到內存 std::cout << printer.CStr() << std::endl; std::cout << "size: " << printer.CStrSize() << std::endl; std::cout << "size: " << strlen(printer.CStr()) + 1 << std::endl; return 0; }
- 編譯運行如下:
g++ tinyxml2.cpp demo01.cpp -o demo01 -std=c++11
五、演示案例2
- 下面的demo02.cpp演示將一段xml字符串寫入本地文件demo02_1.xml、demo02_2.xml中
- Github鏈接:https://github.com/dongyusheng/csdn-code/tree/master/tinyxml2
代碼實現
//demo02.cpp //測試將一段xml字符串寫入本地文件demo02_1.xml、demo02_2.xml中 #include <iostream> #include "tinyxml2.h" int main(void) { const char *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \ <note> \ <to>beijing</to> \ <from>shenzhen</from> \ <heading>Reminder</heading> \ <body>Don't forget the meeting!</body> \ </note>"; tinyxml2::XMLDocument doc; doc.Parse(xml); std::cout << doc.ErrorID() << std::endl; // 1. 第一種刷新到本地 FILE *fp = fopen("demo02_1.xml", "wb"); tinyxml2::XMLPrinter printer(fp); doc.Print(&printer); // 打印到文件,則.CStr()就返回空值了 std::cout << "xml:" << printer.CStr() << std::endl; fclose(fp); // 2. 第二種刷新到本地 doc.SaveFile("demo02_2.xml"); return 0; }
- 編譯運行如下:
g++ tinyxml2.cpp demo02.cpp -o demo02 -std=c++11
六、演示案例3
- 下面的demo03.cpp演示對xml的增刪改查
- Github鏈接:https://github.com/dongyusheng/csdn-code/tree/master/tinyxml2
代碼實現
//demo03.cpp //增刪改查演示版本 #include <iostream> #include "tinyxml2.h" #include <stdio.h> #include <stdlib.h> using namespace tinyxml2; /* enum XMLError { XML_SUCCESS = 0, XML_NO_ATTRIBUTE, XML_WRONG_ATTRIBUTE_TYPE, XML_ERROR_FILE_NOT_FOUND, XML_ERROR_FILE_COULD_NOT_BE_OPENED, XML_ERROR_FILE_READ_ERROR, XML_ERROR_PARSING_ELEMENT, XML_ERROR_PARSING_ATTRIBUTE, XML_ERROR_PARSING_TEXT, XML_ERROR_PARSING_CDATA, XML_ERROR_PARSING_COMMENT, XML_ERROR_PARSING_DECLARATION, XML_ERROR_PARSING_UNKNOWN, XML_ERROR_EMPTY_DOCUMENT, XML_ERROR_MISMATCHED_ELEMENT, XML_ERROR_PARSING, XML_CAN_NOT_CONVERT_TEXT, XML_NO_TEXT_NODE, XML_ELEMENT_DEPTH_EXCEEDED, XML_ERROR_COUNT }; */ //創建XML文件 int createXML(const char* xmlPath) { XMLDocument doc; if (XML_ERROR_FILE_NOT_FOUND != doc.LoadFile(xmlPath)) { std::cout << "file has been existed !" << std::endl; return 0; } //添加聲明 <?xml version="1.0" encoding="UTF-8" ?> XMLDeclaration *declaration = doc.NewDeclaration(); doc.InsertFirstChild(declaration); XMLElement *root = doc.NewElement("Users"); doc.InsertEndChild(root); XMLElement *userNode = doc.NewElement("User"); //添加屬性 userNode->SetAttribute("Name", "dongshao"); userNode->SetAttribute("Password", "pwd"); root->InsertEndChild(userNode); return doc.SaveFile(xmlPath); } void loadXML(const char* xmlPath) { XMLDocument doc; if (doc.LoadFile(xmlPath) != XML_SUCCESS) { std::cout << "load xlm file failed" << std::endl; return; } XMLPrinter printer; doc.Print( &printer); std::cout << printer.CStr(); } //添加性別,號碼,郵箱 再添加一個用戶 int addXML1(const char* xmlPath) { XMLDocument doc; if (doc.LoadFile(xmlPath) != XML_SUCCESS) { std::cout << "load xlm file failed" << std::endl; return -1; } XMLElement *root = doc.RootElement(); XMLElement *userNode = root->FirstChildElement("User"); XMLElement *gender = doc.NewElement("Gender"); XMLText* genderText = doc.NewText("man"); gender->InsertFirstChild(genderText); userNode->InsertFirstChild(gender); XMLElement *mobile = doc.NewElement("Mobile"); mobile->InsertFirstChild(doc.NewText("188****3143")); userNode->InsertEndChild(mobile); XMLElement *email = doc.NewElement("Email"); email->InsertFirstChild(doc.NewText("[email protected]")); userNode->InsertEndChild(email); XMLElement *userNode2 = doc.NewElement("User"); userNode2->SetAttribute("Name", "Tom"); userNode2->SetAttribute("Password", "pwd2"); root->InsertEndChild(userNode2); XMLElement *mobile2 = doc.NewElement("Mobile"); mobile2->InsertFirstChild(doc.NewText("188****3143")); userNode2->InsertEndChild(mobile2); return doc.SaveFile(xmlPath); } //在性別後面添加年齡,再添加一個號碼 int addXML2(const char* xmlPath) { XMLDocument doc; if (doc.LoadFile(xmlPath) != XML_SUCCESS) { std::cout<<"load xml file failed"<<std::endl; return false; } XMLElement* root=doc.RootElement(); XMLElement* userNode=root->FirstChildElement("User"); XMLElement* gender = userNode->FirstChildElement("Gender"); XMLElement* age = doc.NewElement("Age"); age->InsertFirstChild(doc.NewText("18")); userNode->InsertAfterChild(gender,age); XMLElement* mobile = userNode->FirstChildElement("Mobile"); mobile->SetAttribute("Location","home"); XMLElement* mobile1 = doc.NewElement("Mobile"); mobile1->SetAttribute("Location","company"); mobile1->InsertFirstChild(doc.NewText("188****3143")); userNode->InsertAfterChild(mobile, mobile1); return doc.SaveFile(xmlPath); } //刪除第一個號碼,刪除第二個號碼的屬性 int deleteXML(const char* xmlPath) { XMLDocument doc; if (doc.LoadFile(xmlPath) != XML_SUCCESS) { std::cout << "load xlm file failed" << std::endl; return -1; } XMLElement *root = doc.RootElement(); XMLElement *userNode = root->FirstChildElement("User"); XMLElement *mobile = userNode->FirstChildElement("Mobile"); userNode->DeleteChild(mobile); XMLElement *mobile2 = userNode->FirstChildElement("Mobile"); mobile2->DeleteAttribute("Location"); return doc.SaveFile(xmlPath); } //將dongshao的年齡改爲10000歲,將Tom的號碼改爲8888結尾 int updateXML(const char* xmlPath) { XMLDocument doc; if (doc.LoadFile(xmlPath) != XML_SUCCESS) { std::cout << "load xlm file failed" << std::endl; return -1; } XMLElement *root = doc.RootElement(); XMLElement *userNode = root->FirstChildElement("User"); while (userNode != NULL) { if (0 == strncmp("dongshao", (userNode->Attribute("Name")), 11)) { userNode->FirstChildElement("Age")->SetText("10000"); userNode = userNode->NextSiblingElement(); } else if (0 == strncmp("Tom", (userNode->Attribute("Name")), 11)) { userNode->FirstChildElement("Mobile")->SetText("188****8888"); userNode = userNode->NextSiblingElement(); } else { userNode = userNode->NextSiblingElement(); } } return doc.SaveFile(xmlPath); } //將dongshao的信息打印出來 int selectXML(const char* xmlPath) { XMLDocument doc; if(doc.LoadFile(xmlPath)!=XML_SUCCESS) { std::cout<<"load xml file failed"<<std::endl; return false; } XMLElement* root=doc.RootElement(); XMLElement* userNode=root->FirstChildElement("User"); while(userNode != NULL) { if( 0 == strncmp("dongshao",(userNode->Attribute("Name")),11)) { std::cout << userNode->Attribute("Name") << std::endl; std::cout << userNode->Attribute("Password") << std::endl; std::cout << userNode->FirstChildElement("Age")->GetText() << std::endl; std::cout << userNode->FirstChildElement("Gender")->GetText() << std::endl; std::cout << userNode->FirstChildElement("Mobile")->GetText() << std::endl; std::cout << userNode->FirstChildElement("Email")->GetText() << std::endl; userNode = userNode->NextSiblingElement(); } else { userNode = userNode->NextSiblingElement(); } } return 0; } int main( int argc, const char ** argv ) { char xmlPath[] = "./demo03.xml"; /*創建*/ createXML(xmlPath); loadXML(xmlPath); printf("------------------------------\n"); /*增*/ addXML1(xmlPath); loadXML(xmlPath); printf("------------------------------\n"); addXML2(xmlPath); loadXML(xmlPath); printf("------------------------------\n"); /*刪*/ deleteXML(xmlPath); loadXML(xmlPath); printf("------------------------------\n"); /*改*/ updateXML(xmlPath); loadXML(xmlPath); printf("------------------------------\n"); /*查*/ selectXML(xmlPath); return 0; }
- 編譯運行如下:
g++ tinyxml2.cpp demo03.cpp -o demo03 -std=c++11
七、演示案例4
- 下面的demo04.cpp演示在本地創建一個camera_info_1.xml文件並進行增刪改查。demo05.cpp是對demo04.cpp進行改進,操作camera_info_2.xml
- Github鏈接:https://github.com/dongyusheng/csdn-code/tree/master/tinyxml2
代碼實現(demo04.cpp)
//demo04.cpp //增刪改查初級版本 #include <iostream> #include "tinyxml2.h" #define CHECK_TINYXML2_RESULT(ret) \ do \ { \ if (ret != tinyxml2::XML_SUCCESS) \ { \ std::cout << __FUNCTION__ << "(" << __LINE__ << ") failed, ret = " << ret << std::endl; \ return -1; \ } \ } while (0) /** * @brief: 寫相機屬性. 產生完了之後將所有節點掛在p下面 * @param p 某個相機節點 * @param doc 所有的元素屬性以及值均在doc的下面 * @param ipAddr IP地址 * @return: 返回說明 * @retval: 返回值說明 */ static void WriteOneCameraAttibute(tinyxml2::XMLElement *p, tinyxml2::XMLDocument &doc, const char *ipAddr) { const char *subnetMask = "123.45.67.89"; tinyxml2::XMLElement *pDevID = doc.NewElement("DevID"); tinyxml2::XMLText *pDevIdText = doc.NewText("5"); pDevID->InsertEndChild(pDevIdText); p->InsertEndChild(pDevID); tinyxml2::XMLElement *pIpAddr = doc.NewElement("IpAddress"); tinyxml2::XMLText *pIpAddrText = doc.NewText(ipAddr); pIpAddr->InsertEndChild(pIpAddrText); p->InsertEndChild(pIpAddr); tinyxml2::XMLElement *pSubnetMask = doc.NewElement("SubnetMask"); tinyxml2::XMLText *pSubnetMaskText = doc.NewText(subnetMask); pSubnetMask->InsertEndChild(pSubnetMaskText); p->InsertEndChild(pSubnetMask); tinyxml2::XMLElement *pExposureAuto = doc.NewElement("ExposureAuto"); tinyxml2::XMLText *pExposureAutoText = doc.NewText("false"); pExposureAuto->InsertEndChild(pExposureAutoText); p->InsertEndChild(pExposureAuto); tinyxml2::XMLElement *pExposureTime = doc.NewElement("ExposureTime"); tinyxml2::XMLText *pExposureTimeText = doc.NewText("200"); pExposureTime->InsertEndChild(pExposureTimeText); p->InsertEndChild(pExposureTime); tinyxml2::XMLElement *pTriggerMode = doc.NewElement("TriggerMode"); tinyxml2::XMLText *pTriggerModeText = doc.NewText("false"); pTriggerMode->InsertEndChild(pTriggerModeText); p->InsertEndChild(pTriggerMode); } /** * @brief: 將數據寫到某個xml文件中 * @param path xml文件路徑 * @return: 返回說明 * @retval: 返回值說明 */ static int WriteParam(const std::string &path) { tinyxml2::XMLError ret; tinyxml2::XMLDocument doc; const char *declaration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; ret = doc.Parse(declaration); CHECK_TINYXML2_RESULT(ret); tinyxml2::XMLElement *pFirst = doc.NewElement("CameraI"); pFirst->SetAttribute("type", "home"); pFirst->SetAttribute("price", 1000); pFirst->SetAttribute("wifi", true); // 內部插內容 WriteOneCameraAttibute(pFirst, doc, "1.22.32.82"); doc.InsertEndChild(pFirst); tinyxml2::XMLElement *pSecond = doc.NewElement("CameraII"); // 內部插內容 WriteOneCameraAttibute(pSecond, doc, "2.22.32.82"); doc.InsertEndChild(pSecond); tinyxml2::XMLElement *pThree = doc.NewElement("CameraIII"); // 內部插內容 WriteOneCameraAttibute(pThree, doc, "3.22.32.82"); doc.InsertEndChild(pThree); ret = doc.SaveFile(path.c_str()); return 0; } /** * @brief: 讀取每個相機的屬性 * @param p 相機節點指針 * @return: 返回說明 * @retval: 返回值說明 */ static void ReadOneCameraAttribute(const tinyxml2::XMLElement *p) { int devIdContent = p->FirstChildElement("DevID")->IntText(); const char *ipAddrContent = p->FirstChildElement("IpAddress")->GetText(); const char *subnetMaskContent = p->FirstChildElement("SubnetMask")->GetText(); const char *exposureAutoContent = p->FirstChildElement("ExposureAuto")->GetText(); int64_t exposureTimeContent = p->FirstChildElement("ExposureTime")->Int64Text(); bool triggerModeContent = p->FirstChildElement("TriggerMode")->BoolText(); std::cout << "devIdContent(int):\t" << devIdContent << std::endl; std::cout << "ipAddrContent:\t" << ipAddrContent << std::endl; std::cout << "subnetMaskContent:\t" << subnetMaskContent << std::endl; std::cout << "exposureAutoContent:\t" << exposureAutoContent << std::endl; std::cout << "exposureTimeContent(int64_t):\t" << exposureTimeContent << std::endl; std::cout << "triggerModeContent(bool):\t" << ((triggerModeContent == true) ? "true" : "false") << std::endl; } /** * @brief: 讀取解析某路徑的xml文件 * @param path xml文件路徑 * @return: 返回說明 * @retval: 返回值說明 */ static int ReadParam(const std::string &path) { // 導入文件錯誤, 退出 tinyxml2::XMLDocument doc; tinyxml2::XMLError error = doc.LoadFile(path.c_str()); CHECK_TINYXML2_RESULT(error); tinyxml2::XMLElement *pFirst = doc.FirstChildElement("CameraI"); //doc.RootElement();// 等同 tinyxml2::XMLElement *pSecond = doc.FirstChildElement("CameraII"); tinyxml2::XMLElement *pThree = doc.FirstChildElement("CameraIII"); // 分別讀取每個相機的各個屬性 ReadOneCameraAttribute(pFirst); std::cout << "------------------\n"; ReadOneCameraAttribute(pSecond); std::cout << "------------------\n"; ReadOneCameraAttribute(pThree); std::cout << "------------------\n"; return 0; } /** * @brief: 修改相機屬性 * @param p 相機節點指針 * @return: 返回說明 * @retval: 返回值說明 */ static void ModifyOneCamera(tinyxml2::XMLElement *p) { int devId = 4; const char *ipAddr = "139.66.38.13"; const char *subnetMask = "255.0.0.0"; bool exposureAuto = false; int64_t exposureTime = 80; bool triggerMode = false; p->FirstChildElement("DevID")->SetText(devId); p->FirstChildElement("IpAddress")->SetText(ipAddr); p->FirstChildElement("SubnetMask")->SetText(subnetMask); p->FirstChildElement("ExposureAuto")->SetText(exposureAuto); p->FirstChildElement("ExposureTime")->SetText(exposureTime); p->FirstChildElement("TriggerMode")->SetText(triggerMode); } /** * @brief: 修改某xml文件的參數 * @param path xml文件路徑 * @return: 返回說明 * @retval: 返回值說明 */ static void ModifyParam(const std::string &path) { // 導入文件錯誤, 退出 tinyxml2::XMLDocument doc; tinyxml2::XMLError error = doc.LoadFile(path.c_str()); if (error != tinyxml2::XMLError::XML_SUCCESS) return; // 三個相機指針 tinyxml2::XMLElement *pFirst = doc.FirstChildElement("CameraI"); tinyxml2::XMLElement *pSecond = doc.FirstChildElement("CameraII"); tinyxml2::XMLElement *pThree = doc.FirstChildElement("CameraIII"); // 修改 ModifyOneCamera(pFirst); ModifyOneCamera(pSecond); ModifyOneCamera(pThree); doc.SaveFile(path.c_str()); } void testCameraXML() { std::string path = "camera_info_1.xml"; std::cout << "---------------生成一個xml文件------------------" << std::endl; WriteParam(path); std::cout << "--------------寫文件結束,讀取生成的xml文件------------------" << std::endl; ReadParam(path); std::cout << "--------------讀文件結束,修改文件開始------------------" << std::endl; ModifyParam(path); std::cout << "--------------修改文件結束,讀取修改的xml文件------------------" << std::endl; ReadParam(path); } int main(void) { testCameraXML(); return 0; }
- 編譯運行如下:
g++ tinyxml2.cpp demo04.cpp -o demo04 -std=c++11
代碼實現(demo05.cpp)
//demo05.cpp //增刪改查高級版本 #include <iostream> #include "tinyxml2.h" #define CHECK_TINYXML2_RESULT(ret) \ do \ { \ if (ret != tinyxml2::XML_SUCCESS) \ { \ std::cout << __FUNCTION__ << "(" << __LINE__ << ") failed, ret = " << ret << std::endl; \ return -1; \ } \ } while (0) typedef struct cameraInfo { int id; std::string type; std::string ipAddr; std::string subnetMask; bool exposureAuto; int64_t exposureTime; bool triggerMode; float price; } CAMERA_INFO_T; /** * @brief: 寫入類型1 Camera的測試信息 * @param p * @param doc * @return: 返回說明 * @retval: 返回值說明 */ static void WriteCameraI(tinyxml2::XMLElement *p, tinyxml2::XMLDocument &doc) { const char *ipAddr = "178.26.85.83"; const char *subnetMask = "123.45.67.89"; // 1. 創建一個CameraI tinyxml2::XMLElement *cameraI_1 = doc.NewElement("CameraI"); // 2. 封裝CameraI // 寫入屬性 cameraI_1->SetAttribute("type", "home"); cameraI_1->SetAttribute("id", 5); // 寫入IP地址 tinyxml2::XMLElement *pIpAddr = doc.NewElement("IpAddress"); tinyxml2::XMLText *pIpAddrText = doc.NewText(ipAddr); pIpAddr->InsertEndChild(pIpAddrText); cameraI_1->InsertEndChild(pIpAddr); // 寫入子網掩碼 tinyxml2::XMLElement *pSubnetMask = doc.NewElement("SubnetMask"); tinyxml2::XMLText *pSubnetMaskText = doc.NewText(subnetMask); pSubnetMask->InsertEndChild(pSubnetMaskText); cameraI_1->InsertEndChild(pSubnetMask); // 寫入是否自動曝光 tinyxml2::XMLElement *pExposureAuto = doc.NewElement("ExposureAuto"); tinyxml2::XMLText *pExposureAutoText = doc.NewText("false"); pExposureAuto->InsertEndChild(pExposureAutoText); cameraI_1->InsertEndChild(pExposureAuto); // 寫入曝光時長 tinyxml2::XMLElement *pExposureTime = doc.NewElement("ExposureTime"); tinyxml2::XMLText *pExposureTimeText = doc.NewText("200"); pExposureTime->InsertEndChild(pExposureTimeText); cameraI_1->InsertEndChild(pExposureTime); // 寫入觸發模式 tinyxml2::XMLElement *pTriggerMode = doc.NewElement("TriggerMode"); tinyxml2::XMLText *pTriggerModeText = doc.NewText("false"); pTriggerMode->InsertEndChild(pTriggerModeText); cameraI_1->InsertEndChild(pTriggerMode); // 寫入價格 tinyxml2::XMLElement *pPrice = doc.NewElement("Price"); tinyxml2::XMLText *pPriceText = doc.NewText("9.9"); pPrice->InsertEndChild(pPriceText); cameraI_1->InsertEndChild(pPrice); // 3. 將一個CameraI插入到CameraConfig p->InsertEndChild(cameraI_1); // 1. 創建一個CameraI tinyxml2::XMLElement *cameraI_2 = doc.NewElement("CameraI"); // 2. 封裝CameraI // 寫入屬性 cameraI_2->SetAttribute("type", "company"); cameraI_2->SetAttribute("id", 6); // 寫入IP地址 pIpAddr = doc.NewElement("IpAddress"); pIpAddrText = doc.NewText(ipAddr); pIpAddr->InsertEndChild(pIpAddrText); cameraI_2->InsertEndChild(pIpAddr); // 寫入子網掩碼 pSubnetMask = doc.NewElement("SubnetMask"); pSubnetMaskText = doc.NewText(subnetMask); pSubnetMask->InsertEndChild(pSubnetMaskText); cameraI_2->InsertEndChild(pSubnetMask); // 寫入是否自動曝光 pExposureAuto = doc.NewElement("ExposureAuto"); pExposureAutoText = doc.NewText("false"); pExposureAuto->InsertEndChild(pExposureAutoText); cameraI_2->InsertEndChild(pExposureAuto); // 寫入曝光時長 pExposureTime = doc.NewElement("ExposureTime"); pExposureTimeText = doc.NewText("200"); pExposureTime->InsertEndChild(pExposureTimeText); cameraI_2->InsertEndChild(pExposureTime); // 寫入觸發模式 pTriggerMode = doc.NewElement("TriggerMode"); pTriggerModeText = doc.NewText("false"); pTriggerMode->InsertEndChild(pTriggerModeText); cameraI_2->InsertEndChild(pTriggerMode); // 寫入價格 // 3. 將一個CameraI插入到CameraConfig p->InsertEndChild(cameraI_2); } /** * @brief: 寫入類型2 Camera的測試信息 * @param p * @param doc * @return: 返回說明 * @retval: 返回值說明 */ static void WriteCameraII(tinyxml2::XMLElement *p, tinyxml2::XMLDocument &doc) { const char *ipAddr = "2.26.85.83"; const char *subnetMask = "123.45.67.89"; // 1. 創建一個CameraII tinyxml2::XMLElement *cameraII_1 = doc.NewElement("CameraII"); // 2. 封裝CameraII // 寫入設備ID tinyxml2::XMLElement *pDevID = doc.NewElement("DevID"); tinyxml2::XMLText *pDevIdText = doc.NewText("7"); pDevID->InsertEndChild(pDevIdText); cameraII_1->InsertEndChild(pDevID); // 寫入IP地址 tinyxml2::XMLElement *pIpAddr = doc.NewElement("IpAddress"); tinyxml2::XMLText *pIpAddrText = doc.NewText(ipAddr); pIpAddr->InsertEndChild(pIpAddrText); cameraII_1->InsertEndChild(pIpAddr); // 寫入子網掩碼 tinyxml2::XMLElement *pSubnetMask = doc.NewElement("SubnetMask"); tinyxml2::XMLText *pSubnetMaskText = doc.NewText(subnetMask); pSubnetMask->InsertEndChild(pSubnetMaskText); cameraII_1->InsertEndChild(pSubnetMask); // 寫入是否自動曝光 tinyxml2::XMLElement *pExposureAuto = doc.NewElement("ExposureAuto"); tinyxml2::XMLText *pExposureAutoText = doc.NewText("false"); pExposureAuto->InsertEndChild(pExposureAutoText); cameraII_1->InsertEndChild(pExposureAuto); // 寫入曝光時長 tinyxml2::XMLElement *pExposureTime = doc.NewElement("ExposureTime"); tinyxml2::XMLText *pExposureTimeText = doc.NewText("200"); pExposureTime->InsertEndChild(pExposureTimeText); cameraII_1->InsertEndChild(pExposureTime); // 寫入觸發模式 tinyxml2::XMLElement *pTriggerMode = doc.NewElement("TriggerMode"); tinyxml2::XMLText *pTriggerModeText = doc.NewText("false"); pTriggerMode->InsertEndChild(pTriggerModeText); cameraII_1->InsertEndChild(pTriggerMode); // 寫入價格 tinyxml2::XMLElement *pPrice = doc.NewElement("Price"); tinyxml2::XMLText *pPriceText = doc.NewText("9.9"); pPrice->InsertEndChild(pPriceText); cameraII_1->InsertEndChild(pPrice); // 3. 將一個CameraI插入到CameraConfig p->InsertEndChild(cameraII_1); // 1. 創建一個CameraII tinyxml2::XMLElement *cameraII_2 = doc.NewElement("CameraII"); // 2. 封裝CameraII // 寫入設備ID pDevID = doc.NewElement("DevID"); pDevIdText = doc.NewText("8"); pDevID->InsertEndChild(pDevIdText); cameraII_2->InsertEndChild(pDevID); // 寫入IP地址 pIpAddr = doc.NewElement("IpAddress"); pIpAddrText = doc.NewText(ipAddr); pIpAddr->InsertEndChild(pIpAddrText); cameraII_2->InsertEndChild(pIpAddr); // 寫入子網掩碼 pSubnetMask = doc.NewElement("SubnetMask"); pSubnetMaskText = doc.NewText(subnetMask); pSubnetMask->InsertEndChild(pSubnetMaskText); cameraII_2->InsertEndChild(pSubnetMask); // 寫入是否自動曝光 pExposureAuto = doc.NewElement("ExposureAuto"); pExposureAutoText = doc.NewText("false"); pExposureAuto->InsertEndChild(pExposureAutoText); cameraII_2->InsertEndChild(pExposureAuto); // 寫入曝光時長 pExposureTime = doc.NewElement("ExposureTime"); pExposureTimeText = doc.NewText("400"); pExposureTime->InsertEndChild(pExposureTimeText); cameraII_2->InsertEndChild(pExposureTime); // 寫入觸發模式 pTriggerMode = doc.NewElement("TriggerMode"); pTriggerModeText = doc.NewText("false"); pTriggerMode->InsertEndChild(pTriggerModeText); cameraII_2->InsertEndChild(pTriggerMode); // 寫入價格 // 3. 將一個CameraI插入到CameraConfig p->InsertEndChild(cameraII_2); } /** * @brief: 寫入類型Camera的測試信息 * @param path 路徑 * @return: 返回說明 * @retval: 返回值說明 */ static int WriteXML(const std::string &path) { tinyxml2::XMLError ret; tinyxml2::XMLDocument doc; const char *declaration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; ret = doc.Parse(declaration); CHECK_TINYXML2_RESULT(ret); tinyxml2::XMLElement *root = doc.NewElement("CameraConfig"); root->SetAttribute("version", "1.0"); WriteCameraI(root, doc); WriteCameraII(root, doc); doc.InsertEndChild(root); // InsertEndChild 添加節點 ret = doc.SaveFile(path.c_str()); CHECK_TINYXML2_RESULT(ret); return 0; } /** * @brief: 讀取一個camera信息 * @param {type} 形參 參數說明 * @return: 返回說明 * @retval: 返回值說明 */ static void ReadOneCameraXML(const tinyxml2::XMLElement *p) { std::cout << "Model:" << p->Name() << std::endl; const tinyxml2::XMLAttribute *type = p->FindAttribute("type"); if (type) { std::cout << "camera type:\t" << type->Value() << std::endl; } const tinyxml2::XMLAttribute *id = p->FindAttribute("id"); if (id) { std::cout << "camera id:\t" << id->IntValue() << std::endl; } const tinyxml2::XMLElement *devId = p->FirstChildElement("DevID"); if (devId) // 判斷某個元素是否存在 { int devIdContent = devId->IntText(); std::cout << "devIdContent(int):\t" << devIdContent << std::endl; } const char *ipAddrContent = p->FirstChildElement("IpAddress")->GetText(); const char *subnetMaskContent = p->FirstChildElement("SubnetMask")->GetText(); const char *exposureAutoContent = p->FirstChildElement("ExposureAuto")->GetText(); int64_t exposureTimeContent = p->FirstChildElement("ExposureTime")->Int64Text(); bool triggerModeContent = p->FirstChildElement("TriggerMode")->BoolText(); std::cout << "ipAddrContent:\t" << ipAddrContent << std::endl; std::cout << "subnetMaskContent:\t" << subnetMaskContent << std::endl; std::cout << "exposureAutoContent:\t" << exposureAutoContent << std::endl; std::cout << "exposureTimeContent(int64_t):\t" << exposureTimeContent << std::endl; std::cout << "triggerModeContent(bool):\t" << ((triggerModeContent == true) ? "true" : "false") << std::endl; const tinyxml2::XMLElement *pPrice = p->FirstChildElement("Price"); if (pPrice) // 判斷某個元素是否存在 { std::cout << "price(float):\t" << pPrice->FloatText() << std::endl; } } /** * @brief: 遍歷XML * @param path 本地文件路徑 * @return: 返回說明 * @retval: 返回值說明 */ static int ParseXML(const std::string &path) { std::cout << "ParseXML into" << std::endl; tinyxml2::XMLDocument doc; tinyxml2::XMLError error = doc.LoadFile(path.c_str()); CHECK_TINYXML2_RESULT(error); // 如果錯誤則退出 std::cout << "ParseXML:" << std::endl; tinyxml2::XMLElement *root = doc.RootElement(); tinyxml2::XMLElement *element = NULL; element = root->FirstChildElement(); while (true) { if (element) { std::cout << "-------------------------------------" << std::endl; ReadOneCameraXML(element); } else { std::cout << "-------------------------------------" << std::endl; std::cout << "ParseXML finish" << std::endl; break; } element = element->NextSiblingElement(); } return 0; } /** * @brief: 修改一個CameraI * @param {type} 形參 參數說明 * @return: 返回說明 * @retval: 返回值說明 */ static void ModifyOneCameraById(tinyxml2::XMLElement *root, tinyxml2::XMLDocument &doc, const CAMERA_INFO_T &cameraInfo) { tinyxml2::XMLElement *element = NULL; element = root->FirstChildElement(); bool isFindId = false; while (true) { if (element) { const tinyxml2::XMLAttribute *id = element->FindAttribute("id"); if (id) { std::cout << "current id:\t" << id->IntValue() << std::endl; if (id->IntValue() == cameraInfo.id) { std::cout << "Find id:\t" << id->IntValue() << std::endl; isFindId = true; break; } } const tinyxml2::XMLElement *devId = element->FirstChildElement("DevID"); if (devId) // 判斷某個元素是否存在 { std::cout << "current id:\t" << id->IntValue() << std::endl; if (id->IntValue() == cameraInfo.id) { std::cout << "Find id:\t" << id->IntValue() << std::endl; isFindId = true; break; } } } else { std::cout << "-------------------------------------" << std::endl; std::cout << "Find XML finish, not find id:\t" << cameraInfo.id << std::endl; break; } // element = root->NextSiblingElement(); std::cout << "----------NextSiblingElement------------" << std::endl; element = element->NextSiblingElement(); // 兄弟節點 } if (isFindId) { std::cout << "isFindId: " << isFindId << std::endl; std::cout << "ipAddr: " << cameraInfo.ipAddr.c_str() << std::endl; element->FirstChildElement("IpAddress")->SetText(cameraInfo.ipAddr.c_str()); element->FirstChildElement("SubnetMask")->SetText(cameraInfo.subnetMask.c_str()); element->FirstChildElement("ExposureAuto")->SetText(cameraInfo.exposureAuto); element->FirstChildElement("ExposureTime")->SetText(cameraInfo.exposureTime); element->FirstChildElement("TriggerMode")->SetText(cameraInfo.triggerMode); element->SetAttribute("type", cameraInfo.type.c_str()); tinyxml2::XMLElement *pPrice = element->FirstChildElement("Price"); if (pPrice) { pPrice->SetText(cameraInfo.price); } else // 查找失敗則說明沒有該屬性,需要添加 { pPrice = doc.NewElement("Price"); char cpriceBuf[20]; sprintf(cpriceBuf, "%0.2f", cameraInfo.price); std::cout << " Add price: " << cpriceBuf << std::endl; tinyxml2::XMLText *pPriceText = doc.NewText(cpriceBuf); tinyxml2::XMLComment *pPriceComment = doc.NewComment("add price"); element->InsertEndChild(pPriceComment); pPrice->InsertEndChild(pPriceText); element->InsertEndChild(pPrice); } } } /** * @brief: 修改指定ID的camera的參數 * @param path 路徑 * @param camearInfo 新的參數信息 * @return: 返回說明 * @retval: 返回值說明 */ static int ModifyXMLById(const std::string &path, const CAMERA_INFO_T &camearInfo) { // 導入文件錯誤, 退出 tinyxml2::XMLDocument doc; tinyxml2::XMLError error = doc.LoadFile(path.c_str()); CHECK_TINYXML2_RESULT(error); tinyxml2::XMLElement *root = doc.FirstChildElement("CameraConfig"); ModifyOneCameraById(root, doc, camearInfo); error = doc.SaveFile(path.c_str()); CHECK_TINYXML2_RESULT(error); return 0; } void testCameraXML() { std::string path = "camera_config_2.xml"; // // std::string path = "camera_info.xml"; std::cout << "---------------生成一個xml文件------------------" << std::endl; WriteXML(path); std::cout << "--------------寫文件結束,讀取生成的xml文件------------------" << std::endl; ParseXML(path); std::cout << "--------------讀文件結束,根據ID查找camera並修改--------------" << std::endl; CAMERA_INFO_T cameraInfo; cameraInfo.id = 6; cameraInfo.type = "hotel"; cameraInfo.ipAddr = "111.26.85.8"; cameraInfo.subnetMask = "111.26.85.255"; cameraInfo.exposureAuto = true; cameraInfo.triggerMode = false; cameraInfo.price = 100; ModifyXMLById(path, cameraInfo); std::cout << "--------------修改文件結束,讀取修改的xml文件------------------" << std::endl; ParseXML(path); } int main(void) { testCameraXML(); return 0; }
- 編譯運行如下:
g++ tinyxml2.cpp demo05.cpp -o demo05 -std=c++11