做服务器肯定会涉及到游戏配表,而读取游戏配表是一个必备技能;
之前一直都是采用TinyXml直接读,匹配字符串,每次加个表都是一大坨代码,看着也是心累;
因此利用了闲暇的时间封装了一个 xml配置表 读取类;
1.支持 按照 列*行的读取方法
2.支持 按照 "标题"*行的读取方法
3.支持 按照 列*行的修改
4.支持 按照 "标题"*行的修改
//例子用的xml , 库用的是 tinyxml 2.5.3
<?xml version="1.0" encoding="gbk" standalone="yes" ?> <config> <Quest Quest_ID="1" Quest_Star="1" Quest_Limit="0" Quest_Type="6" Quest_TarID="0" Quest_Tar_Num="100" Award_Type="2" Award_ID="1" Awa_Num="5000" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="2" Quest_Star="1" Quest_Limit="0" Quest_Type="6" Quest_TarID="0" Quest_Tar_Num="500" Award_Type="2" Award_ID="1" Awa_Num="10000" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="3" Quest_Star="1" Quest_Limit="0" Quest_Type="10" Quest_TarID="0" Quest_Tar_Num="3" Award_Type="2" Award_ID="1" Awa_Num="6000" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="4" Quest_Star="1" Quest_Limit="0" Quest_Type="10" Quest_TarID="0" Quest_Tar_Num="5" Award_Type="2" Award_ID="1" Awa_Num="8000" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="5" Quest_Star="1" Quest_Limit="0" Quest_Type="11" Quest_TarID="0" Quest_Tar_Num="1" Award_Type="2" Award_ID="1" Awa_Num="10000" Quest_Des="击杀%dBOSS" bModify="0" bNew="0" /> <Quest Quest_ID="6" Quest_Star="1" Quest_Limit="0" Quest_Type="11" Quest_TarID="0" Quest_Tar_Num="2" Award_Type="2" Award_ID="1" Awa_Num="15000" Quest_Des="击杀%dBOSS" bModify="0" bNew="0" /> <Quest Quest_ID="7" Quest_Star="1" Quest_Limit="0" Quest_Type="6" Quest_TarID="0" Quest_Tar_Num="100" Award_Type="2" Award_ID="2" Awa_Num="10" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="8" Quest_Star="1" Quest_Limit="0" Quest_Type="6" Quest_TarID="0" Quest_Tar_Num="500" Award_Type="2" Award_ID="2" Awa_Num="25" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="9" Quest_Star="1" Quest_Limit="0" Quest_Type="10" Quest_TarID="0" Quest_Tar_Num="3" Award_Type="2" Award_ID="2" Awa_Num="15" Quest_Des="击杀%d赏金" bModify="0" bNew="0" /> <Quest Quest_ID="10" Quest_Star="1" Quest_Limit="0" Quest_Type="10" Quest_TarID="0" Quest_Tar_Num="5" Award_Type="2" Award_ID="2" Awa_Num="20" Quest_Des="击杀%d赏金" bModify="0" bNew="0" /> <Quest Quest_ID="11" Quest_Star="1" Quest_Limit="0" Quest_Type="11" Quest_TarID="0" Quest_Tar_Num="1" Award_Type="2" Award_ID="2" Awa_Num="25" Quest_Des="击杀%d" bModify="0" bNew="0" /> <Quest Quest_ID="12" Quest_Star="1" Quest_Limit="0" Quest_Type="11" Quest_TarID="0" Quest_Tar_Num="2" Award_Type="2" Award_ID="2" Awa_Num="40" Quest_Des="击杀%d" bModify="0" bNew="0" /> </config>
下面就直接上代码;
#pragma once #pragma warning(disable:4786) #pragma warning(disable:4503) #include "tinyxml.h" #include <map> #include <string> using namespace std; class CRowStr{ public: CRowStr(int row,string title) { _row=row; _title=title; } bool operator<( const CRowStr& a) const { if(this->_row<a._row) return true; else return false; }; int _row;//行 string _title;//标题 }; typedef map<CRowStr, string> mpCfgRow; typedef map<int, mpCfgRow*> mpCfgList; //默认从第1列开始读取 #define ROWBEGIN 1 //默认从第1行开始读取 #define LINEBEGIN 1 //非元素模式从1000开始 #define NEXTBEGIN 1000 //暂时不支持非元素模式 class CXmlFileReader { public: CXmlFileReader(const char* _filename,const int _flag=1); ~CXmlFileReader(); //获取第line行的_title字段的数据 char* GetValueByTitle(const char*_title/*字段*/, const int _line=LINEBEGIN/*行数*/); //获取第line行的_row列数据 char* GetValueByRow(const int _row=ROWBEGIN/*列数*/, const int _line=LINEBEGIN/*行数*/); //设置第line行的_title字段的数据 bool SetValueByTitle(const char *_value/*内容*/,const char*_title/*字段*/,const int _line=LINEBEGIN/*行数*/); //设置第line行的_row列数据 bool SetValueByRow(const char *_value/*内容*/,const int _row=ROWBEGIN/*列数*/,const int _line=LINEBEGIN/*行数*/); int GetLines();//获取行数 int GetRows();//获取列数 private: void _loadFile(); void _clearMap(); void _example();//例子 private: bool m_load_ok; string m_path; int m_Flag; int m_Maxlines; int m_Maxrows; mpCfgList* m_config_map; };
下面是.cpp文件
#include "XmlControl.h" CXmlFileReader::CXmlFileReader(const char* _filename,const int _flag) { m_Maxlines=0; m_Maxrows=0; m_config_map = new mpCfgList; m_path = string(_filename); m_Flag = _flag; _loadFile(); } CXmlFileReader::~CXmlFileReader() { _clearMap(); } void CXmlFileReader::_example() { //用法 string filePath = "D:\Quest.xml"; CXmlFileReader Reader(filePath.c_str()); //读取 string _desRowOld(Reader.GetValueByRow(10,2)); string _desTitleOld(Reader.GetValueByTitle("Quest_Des",3)); //设置节点值 Reader.SetValueByTitle("Testtitle","Quest_Des",3); Reader.SetValueByRow("Testrow",10,2); //读取 string _desRowNew(Reader.GetValueByRow(10,2)); string _desTitleNew(Reader.GetValueByTitle("Quest_Des",3)); } int CXmlFileReader::GetLines() { if(!m_load_ok) return 0; return m_Maxlines; } int CXmlFileReader::GetRows() { if(!m_load_ok) return 0; return m_Maxrows; } char* CXmlFileReader::GetValueByTitle(const char* title,const int line) { if (!m_load_ok) return NULL; char* value = NULL; mpCfgList::iterator itLine = m_config_map->find(line); if(itLine == m_config_map->end()) return NULL; mpCfgRow* mpRowValue = itLine->second; mpCfgRow::iterator itValue = mpRowValue->begin(); for (; itValue != mpRowValue->end(); itValue++){ const CRowStr key=itValue->first; if (key._title==string(title)){ value = (char*) itValue->second.c_str(); break; } } return value; } char* CXmlFileReader::GetValueByRow(const int row, const int line) { if (!m_load_ok) return NULL; char* value = NULL; mpCfgList::iterator itLine = m_config_map->find(line); if(itLine == m_config_map->end()) return NULL; mpCfgRow* mpRowValue = itLine->second; mpCfgRow::iterator itValue = mpRowValue->begin(); for (; itValue != mpRowValue->end(); itValue++){ const CRowStr key = itValue->first; if(key._row == row){ value = (char*) itValue->second.c_str(); break; } } return value; } bool CXmlFileReader::SetValueByTitle(const char * value,const char* title,const int line) { TiXmlDocument _doc; int _curline=line; int _flag = m_Flag; if(!_doc.LoadFile(m_path.c_str())||!title||!value) return false; //改xml值 TiXmlElement* _pelement = _doc.RootElement(); //root while(_flag--){ _pelement = _pelement->FirstChildElement(); //指向下一个 } while(_pelement){ TiXmlAttribute* _attributeOfStudent = _pelement->FirstAttribute(); //获得每一级的各种属性 if(--_curline>0){ _pelement = _pelement->NextSiblingElement(); continue; } while(_attributeOfStudent){ if(string(_attributeOfStudent->Name())==title){ _attributeOfStudent->SetValue(value); break; } _attributeOfStudent = _attributeOfStudent->Next();//指向下一个元素 } break; } //保存 if(!_doc.SaveFile(m_path.c_str())) return false; //改内存里的值 mpCfgList::iterator itLine = m_config_map->find(line); if(itLine == m_config_map->end()) return NULL; mpCfgRow* mpRowValue = itLine->second; mpCfgRow::iterator itValue = mpRowValue->begin(); for (; itValue != mpRowValue->end(); itValue++){ const CRowStr key = itValue->first; string _strtile = string(title); if (key._title==_strtile){ string _newValue = string(value); itValue->second = _newValue; break; } } return true; } bool CXmlFileReader::SetValueByRow(const char * value,const int row,const int line) { TiXmlDocument _doc; int _curline=line; int _currow=row; int _flag = m_Flag; if(!_doc.LoadFile(m_path.c_str())||!value) return false; //改xml值 TiXmlElement* _pelement = _doc.RootElement(); while(_flag--){ _pelement = _pelement->FirstChildElement(); } while(_pelement){ TiXmlAttribute* _attributeOfStudent = _pelement->FirstAttribute(); if(--_curline>0){ _pelement = _pelement->NextSiblingElement(); continue; } while(_attributeOfStudent){ if(--_currow>0){ _attributeOfStudent = _attributeOfStudent->Next(); continue; } _attributeOfStudent->SetValue(value); break; } break; } //保存 if(!_doc.SaveFile(m_path.c_str())) return false; //改内存里的值 mpCfgList::iterator itLine = m_config_map->find(line); if(itLine == m_config_map->end()) return NULL; mpCfgRow* mpRowValue = itLine->second; mpCfgRow::iterator itValue = mpRowValue->begin(); for (; itValue != mpRowValue->end(); itValue++){ const CRowStr key = itValue->first; if(key._row==row){ string _newValue = string(value); itValue->second = _newValue; break; } } return true; } void CXmlFileReader::_clearMap() { if(!m_config_map) return; mpCfgList::iterator it = m_config_map->begin(); for (; it != m_config_map->end(); it++){ delete it->second; } delete m_config_map; m_config_map = NULL; } void CXmlFileReader::_loadFile() { int _flag = m_Flag; TiXmlDocument _doc; int _line=LINEBEGIN; //int _nxline=NEXTBEGIN; int _row=ROWBEGIN; if(!_doc.LoadFile(m_path.c_str())){ m_load_ok=false; return; } TiXmlElement* _pelement=_doc.RootElement(); //root while(_flag--){ _pelement=_pelement->FirstChildElement();//指向下一个大节点 } switch (_pelement->Type()) { case TiXmlText::DOCUMENT:break; case TiXmlText::DECLARATION:break; case TiXmlText::TEXT:break; case TiXmlText::UNKNOWN:break; case TiXmlText::COMMENT:break; case TiXmlText::ELEMENT: { while(_pelement){ TiXmlAttribute* _attributeOfStudent=_pelement->FirstAttribute(); //获得每一级的各种属性 if (_attributeOfStudent) { mpCfgRow* mpRowValue= new mpCfgRow(); int _rowdex=ROWBEGIN; while (_attributeOfStudent){ CRowStr _rowinfo(_rowdex++,string(_attributeOfStudent->Name())); mpRowValue->insert(make_pair(_rowinfo,string(_attributeOfStudent->Value())));//存储第_line行的所有列 _attributeOfStudent=_attributeOfStudent->Next();//指向下一个元素 ++_row; } _pelement=_pelement->NextSiblingElement(); m_config_map->insert(make_pair(_line++,mpRowValue));//存储_line行的所有元素 } else { /*mpCfgRow* mpRowValue= new mpCfgRow(); mpRowValue->insert(make_pair(string(_pelement->Value()), string(_pelement->FirstChild()->Value())));//存储第_line行的所有列 _pelement=_pelement->NextSiblingElement(); m_config_map->insert(make_pair(_nxline++,mpRowValue));//存储_line行的所有元素 */ } } m_Maxlines=_line-LINEBEGIN; m_Maxrows=(_row-ROWBEGIN)/m_Maxlines; m_load_ok=true; } break; } }