C++解析XML, TINYXML2的使用

C++解析XML, TINYXML2的使用

学习使用tinyxml2,参考https://www.cnblogs.com/happykoukou/p/6307257.html,以及官方tinyxml2的test。

主要知识:

XMLDocument doc;//创建一个dom对象
doc.LoadFile();
doc.Parse(); //将字符串转为dom对象
auto key = doc.NewElement(const char* keyName);//创建一个key
doc.NewText(const char*);//创建一个value
InsertEndChild(key)
FirstChildElement(const char*);
GetText();
SetText(const char*);
NextSiblingElement();//兄弟节点
country.hpp

#pragma once
 
//删除指针
#define SAFE_DELETE(pRet) if(pRet != NULL) {delete pRet;pRet = NULL;}
//检查xml中的键是否存在,xml的结构已知,若不存在,直接退出
#define KEY_IS_NULL(key) if(key == nullptr){printf("%s is not found\n",#key);exit(-1);}
 
//为了简单化,以下几个类全部成员函数为public
class Province;
class City;
 
class City
{
public:
    std::string name;
    City(const std::string &name):name(name){}
};
 
class Province
{
public:
    std::string name;
    std::vector<City> vCities;
    Province(const std::string &name):name(name){}
    Province(){}
};
 
class Country
{
public:
    std::string name;
    std::vector<Province> vProvinces;
 
public:
    Country(const std::string &name):name(name){}
    Country(){}
    
    /**
     *  将本类的成员变量序列化到一个固定格式的xml文件中
     *  采用模板,可以不需要写 tinyxml2的头文件
     */
    template<typename T>
    int parseXML(T &doc, const std::string &fileName)
    {
        //xml头
        //R"(string)", string可以以原来的形式存在,“” 不需要转义符
        const char *declaration = R"(<?xml version="1.0" encoding="UTF-8"?>)";
        
        //将字符串解析到dom对象中
        doc.Parse(declaration);
 
        //new 一个 key
        //序列化std::string name;
        auto roof = doc.NewElement("country");
        auto keyCountryName = doc.NewElement("name");
        
        //插入value
        keyCountryName->InsertEndChild(doc.NewText(name.c_str()));
        
        //插入</>
        roof->InsertEndChild(keyCountryName);
        doc.InsertEndChild(roof);
 
        //序列化std::vector<Province> vProvinces;
        for(auto province : vProvinces)
        {
            auto keyProvince = doc.NewElement("province");
            roof->InsertEndChild(keyProvince);
            auto keyProvinceName = doc.NewElement("name");
            keyProvinceName->InsertEndChild(doc.NewText(province.name.c_str()));
            keyProvince->InsertEndChild(keyProvinceName);
            
            auto keyCities = doc.NewElement("cities");
            keyProvince->InsertEndChild(keyCities);
 
            //序列化std::vector<City> vCities;
            for(auto city : province.vCities)
            {
                auto keyCity = doc.NewElement("city");
                keyCity->InsertEndChild(doc.NewText(city.name.c_str()));
                keyCities->InsertEndChild(keyCity);
            }
        }
        //保存为xml文件
        return doc.SaveFile(fileName.c_str());
    }
 
    //反序列化xml文件成一个对象
    template<typename T>
    int convertXMLToObject(T &doc, const std::string &fileName)
    {
        int ret = doc.LoadFile(fileName.c_str());
        if(ret)
        {
            return ret;
        }
 
        //查找key,如果不存在,则退出程序。
        auto keyCountry  = doc.FirstChildElement("country");
        KEY_IS_NULL(keyCountry);
        auto keyCountryName = keyCountry->FirstChildElement("name");
        KEY_IS_NULL(keyCountryName);
        auto countryName = keyCountryName->GetText();
        if(countryName == nullptr)
        {
            return -1;
        }
        this->name = countryName;
        auto keyProvince = keyCountry->FirstChildElement("province");
 
        //反序列化std::vector<Province> vProvinces;
        while(keyProvince != nullptr)
        {            
            auto keyProvinceName = keyProvince->FirstChildElement("name");
            KEY_IS_NULL(keyProvinceName);
 
            auto provinceName = keyProvinceName->GetText();
            if(provinceName != nullptr)
            {
                Province province(provinceName);
                auto keyCities = keyProvince->FirstChildElement("cities");
                KEY_IS_NULL(keyCities);
                auto keyCity = keyCities->FirstChildElement("city");
                KEY_IS_NULL(keyCity);
 
                //反序列化std::vector<City> vCities;
                while(keyCity != nullptr)
                {
                    auto cityName = keyCity->GetText();
                    if(cityName != nullptr)
                    {
                        City city(cityName);
                        province.vCities.push_back(city);
                    }
 
                    //继续查找兄弟节点
                    keyCity = keyCity->NextSiblingElement(); 
                }
                this->vProvinces.push_back(province);
            }
 
            //继续查找兄弟节点
            keyProvince = keyProvince->NextSiblingElement();
        }
 
        return 0; 
    }
 
    //序列化对象到string
    std::string toString()
    {
        std::string s; 
        if(!name.empty())
        {
            s+= "country name: ";
            s+= name;
        }
        if(!vProvinces.empty())
        {
            for(auto province : vProvinces)
            {
                s+= " province name :";
                s+= province.name;
                if(!province.vCities.empty())
                {
                    s+= " city name: ";
                    for(auto city : province.vCities)
                    {
                        s+= city.name;
                        s+= " ";
                    }
                }
            }
        }
        return s;
    }
 
};
test.cpp

#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include "../tinyxml2.h"
 
#include "country.hpp"
 
using namespace tinyxml2;
using namespace std;
 
#define EXIT_ABNOEMAL(msg) {printf("%s\n", msg); return -1;}
 
//构造一个country
Country* getCountry(const string &name)
{
    auto country = new Country(name);
 
    City haerbing("哈尔滨");
    City daqing("大庆");
    Province heilongjing("黑龙江");
    heilongjing.vCities.push_back(haerbing);
    heilongjing.vCities.push_back(daqing);
 
    City guangzhou("广州");
    City shenzhen("深圳");
    City zhuhai("珠海");
    Province guangdong("广东");
    guangdong.vCities.push_back(guangzhou);
    guangdong.vCities.push_back(shenzhen);
    guangdong.vCities.push_back(zhuhai);
 
    City taibei("台北");
    City gaoxiong("高雄");
    Province taiwan("台湾");
    taiwan.vCities.push_back(gaoxiong);
    taiwan.vCities.push_back(taibei);
 
    City wulumuqi("乌鲁木齐");
    Province xinjiang("新疆");
    xinjiang.vCities.push_back(wulumuqi);
    
    country->vProvinces.push_back(xinjiang);
    country->vProvinces.push_back(heilongjing);
    country->vProvinces.push_back(guangdong);
    country->vProvinces.push_back(taiwan);
    
    return country;
}
 
//序列化对象到xml
int parseCountryToXml(Country *country, const string &filePath)
{
    XMLDocument doc;
    //调用country的序列化函数
    int ret = country->parseXML(doc, filePath);
    return ret;
}
 
//反序列化到对象
int readXMLToCountry(Country * country, const string &filePath)
{
    XMLDocument doc;
    //调用对象的反序列花方法
    int ret = country->convertXMLToObject(doc, filePath);
    return ret;
}
 
int main()
{
    const string fileName = "../test/country.xml";
 
    //将中国对象保存到xml中
    auto zhongguo = getCountry("zhongguo");
    int ret;
    ret = parseCountryToXml(zhongguo, fileName);
    if(ret)
    {
        EXIT_ABNOEMAL("convert to xml error!");
    }
 
    //从上面的xml中反序列化成china对象
    Country *china = new Country();
    ret = readXMLToCountry(china, fileName);
    if(ret)
    {
        EXIT_ABNOEMAL("convert to Object error!");
    }
 
    //输出china对象
    string s = china->toString();
    cout<<s<<"\n";
 
    //安全删除指针
    SAFE_DELETE(zhongguo);
    SAFE_DELETE(china);
    return 0;
}
结果:

country.xml

<?xml version="1.0" encoding="UTF-8"?>
<country>
    <name>zhongguo</name>
    <province>
        <name>新疆</name>
        <cities>
            <city>乌鲁木齐</city>
        </cities>
    </province>
    <province>
        <name>黑龙江</name>
        <cities>
            <city>哈尔滨</city>
            <city>大庆</city>
        </cities>
    </province>
    <province>
        <name>广东</name>
        <cities>
            <city>广州</city>
            <city>深圳</city>
            <city>珠海</city>
        </cities>
    </province>
    <province>
        <name>台湾</name>
        <cities>
            <city>高雄</city>
            <city>台北</city>
        </cities>
    </province>
</country>

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值