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

一、TinyXml2库概述

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

库的安装

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

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

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

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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第1张图片

  • 默认情况下,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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第2张图片

Linux(程序设计):32---TinyXml2库(C++操作XML)_第3张图片

  • 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 = "";
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 
#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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第4张图片

五、演示案例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 
#include "tinyxml2.h"

int main(void)
{
    const char *xml = "   \
                                              \
                            beijing             \
                            shenzhen           \
                            Reminder \
                            Don't forget the meeting! \
                        ";
    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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第5张图片

六、演示案例3

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

代码实现

//demo03.cpp
//增删改查演示版本
#include 
#include "tinyxml2.h"
#include 
#include 

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;
    }

    //添加声明 
    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"<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"<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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第6张图片

七、演示案例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 
#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 = "";
    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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第7张图片 Linux(程序设计):32---TinyXml2库(C++操作XML)_第8张图片

代码实现(demo05.cpp)

//demo05.cpp
//增删改查高级版本
#include 
#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 = "";
    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

Linux(程序设计):32---TinyXml2库(C++操作XML)_第9张图片

你可能感兴趣的:(Linux(程序设计))