Linux(程序设计):32—TinyXml2库(C++操作XML)

一、TinyXml2库概述

  • TinyXML2 是简单实用的开源的 C++XML 文件解析库,可以很方便的应用到现有的项目之中。TinyXML2 解析器相对 TinyXML1 在代码上是完全重写,使其更适合于游戏开发中使用。它使用更少的内存,更快,并使用更少的内存分配

库的安装

  • 通过下面进行下载:
1
git clone https://github.com/leethomason/tinyxml2.git

  • 下载完成之后进入目录进行编码
1
2
3
cd tinyxml2/

make
  • 编译完成之后执行下面的可执行程序是否编译成功
1
./xmltest

  • 编译成功之后进行安装
1
sudo make install

  • 默认情况下,TinyXml2库的头文件安装在/usr/local/include/目录下,动态库文件安装在/usr/local/lib/目录下

编译带有TinyXml2库的C++程序

  • 有两种方式:
    • ①方式一:像上面一样,将TinyXml2库安装,然后将TinyXml2库源码目录下的tinyxml2.cpp同时拷贝到自己的项目目录下
    • ②方式二:不用像上面一样安装TinyXml2库,直接将TinyXml2库源码目录下的tinyxml2.h和tinyxml2.c文件拷贝到项目下就可以编译使用了
  • 编译程序时使用下面的命令:
1
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的两种方法

  • 方式一:从本地文件中读取
1
2
3
tinyxml2::XMLDocument doc;
doc.LoadFile( "test.xml" );
std::cout << doc.ErrorID() << std::endl;

  • 方式二:从内存中加载XML
1
2
3
4
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

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//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;
}
  • 编译运行如下:
1
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

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//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;
}
  • 编译运行如下:
1
g++  tinyxml2.cpp demo02.cpp -o demo02 -std=c++11

六、演示案例3

  • 下面的demo03.cpp演示对xml的增删改查
  • Github链接:https://github.com/dongyusheng/csdn-code/tree/master/tinyxml2

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//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;
}
  • 编译运行如下:
1
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)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//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;
}
  • 编译运行如下:
1
g++  tinyxml2.cpp demo04.cpp -o demo04 -std=c++11

代码实现(demo05.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
//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;
}
  • 编译运行如下:
1
g++  tinyxml2.cpp demo05.cpp -o demo05 -std=c++11