一、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