xml的读写是服务器开发必须要有的一个坑了,xml说白了就是文本内容的一种格式。将文本内容分为不同的节点,每个节点可以由自己的子节点以及属性项。这样当我们读取以及使用的时候就能读取不同的节点,以及加载其相应的属性项。
xml的文本内容多种多样,但说白了就是让程序运行的某些内容可修改。例如你们服务器开通会员有时候是60,搞活动了就做成35块。那你就可以用这个xml作为各种商品价格的文本存储,然后从xml读入商品价格到服务器,当你这个价格需要更改时,你在服务器提供一个接口,用作重新读取xml配置的。这就是服务器热更的一种形式。 客户端读取服务器传来的内容,而服务器读取xml的文本内容,xml可更新重读。
这里主要提c++对于xml的读写,常见的xml读写有好几个库。其中最为知名的大概就是tinyxml以及rapidxml。rapidxml的读入速度非常快,因此作为读入的库最好不过,但是写入的语法稍微复杂一点,tinyxml的读写速度步入rapidxmnl,不过写的语句要规范一点。这两个在项目里面一个作为写(xls生成xml)一个作为读,倒是一个不错选择。
下面先来介绍rpaidxml的用法:
首先,在需要读到xml的地方,需要加入以下上个头文件:
#include "NFComm/RapidXML/rapidxml.hpp"
#include "NFComm/RapidXML/rapidxml_print.hpp"
#include "NFComm/RapidXML/rapidxml_utils.hpp"
2.使用ReadConfig()初始化所有装xml内容的容器,调用读入xml相应的函数使用。当需要热更配置时直接调用ReadConfig。
bool NFCAuctionModule::ReadConfig()
{
numericalValue.clear();
SpecialValue.clear();
permitSellEquip.clear();
timeLimt.clear();
mxEquipConfig.clear();
std::string strEquipPath = pPluginManager->GetConfigPath();
strEquipPath += "./Ini/Common/abc.xml";
LoadAbcConfig(strEquipPath);
strEquipPath = pPluginManager->GetConfigPath();
strEquipPath += "./Ini/Common/Shop.xml";
LoadEquipConfig(strEquipPath);
return true;
}
3.使用函数读取xml。
rapidxml::file<> xFileSource(strPath.c_str()); //读入文件地址,如果文件不存在会在此处报错
rapidxml::xml_document<> xFileDoc;//文件结构体
xFileDoc.parse<0>(xFileSource.data()); //解析所传入地址的xml,如果xml语法有错会在此处报错
rapidxml::xml_node<>* root = xFileDoc.first_node(); //指向xml的第一个节点,即根节点
rapidxml::xml_node<>* fNode = root->first_node("AuctionLimt");
//指向根结点的第一个子节点,填入string后则读取特有节点
//循环读取fNode下面的子节点,其中next_sibling()指向下一个兄弟节点,若fNodeEX空则不读取。
for (rapidxml::xml_node<>* fNodeEX = fNode->first_node(); fNodeEX; fNodeEX = fNodeEX->next_sibling())
{
std::string strId = fNodeEX->first_attribute("TimeLimt")->value();
//读入特定节点的属性TimeLimt 提出属性的值,注意返回值均为string
timeLimt.push_back(lexical_cast<int>(strId));
}
4.上面便是一个完整的xml读写流程,其中,可以看出来,rapidxml对节点和属性都以指针的方式操作,并且节点以及属性都是一个相应的结构体,有相应的函数。下面再来浅谈一下其它函数的使用。
先从node来说:
->append_attribute(追加加入属性 rapidxml::xml_attribute<>*);
->insert_attribute(插入属性节点,where前 rapidxml::xml_attribute<>* where,rapidxml::xml_attribute<>* attribute);
->append_node(加入子节点!! rapidxml::xml_node<>* );
->insert_attribute(用法同上)
//last_node与last_attribute的用法与first相近,这里不介绍了。
(prepend_attribute,prepend_node,previous_sibling)
//上一个属性节点,上一个子节点,上一个兄弟节点。可以看出node的容器是一个双端队列,并且储存了父亲节点的指针。
->name(返回节点名字,name_size可知道名字大小)
->parent()返回父亲节点。
->remove_node(rapidxml::xml_node<>* ),->remove_attribute(rapidxml::xml_attribute<>*)
->remove_first_attribute(),->remove_all_attributes()
->remove_first_node(), ->remove_all_node()
//上面这些均为删除的函数
attribute节点:
->parent() //属性对应的父节点
->value_size() //值大小
->name() //属性名字
->next_attribute(),->previous_attribute() //前后的属性节点