学习使用tinyxml2,参考https://www.cnblogs.com/happykoukou/p/6307257.html,以及官方tinyxml2的test。
主要知识:
XMLDocument doc
doc.LoadFile()
doc.Parse()
auto key = doc.NewElement(const char* keyName)
doc.NewText(const char*)
InsertEndChild(key)
FirstChildElement(const char*)
GetText()
SetText(const char*)
NextSiblingElement()
country.hpp
//删除指针
//检查xml中的键是否存在,xml的结构已知,若不存在,直接退出
//为了简单化,以下几个类全部成员函数为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
using namespace tinyxml2
using namespace std
//构造一个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>