前两天因工作需要写了个xml配置脚本解析的功能类,虽说有N种方式可以实现,但考虑到 Boost库在此方面的易操作性(虽支持不够健全,如Unicode支持等)所以封装了一下,具体如下: //CProcessXmlConfigFile.h(此类由Dll导出) #i nclude "stdafx.h" #pragma once #i nclude <boost/noncopyable.hpp> #i nclude <boost/property_tree/ptree.hpp> #i nclude <boost/property_tree/xml_parser.hpp> #i nclude <boost/tuple/tuple.hpp> #i nclude <boost/shared_ptr.hpp> #i nclude <list> #i nclude "header.h" #define MAX_PANLIST_NUM 9 //默认面板个数 #define MAX_FNAME_LEN 256 //文件名长度宏 using namespace boost::property_tree; typedef ptree xmlParser; typedef vector<string> panNames_t; typedef boost::shared_ptr<string> sh_pstr; typedef boost::tuples::tuple<sh_pstr, size_t, sh_pstr> node_t; typedef std::list<node_t > ptree_nodes_t; ////////////////////////////////////////////////////////////////////////// class AFX_EXT_CLASS CProcessXmlConfigFile : private boost::noncopyable { public: virtual ~CProcessXmlConfigFile(void); //获取类唯一实例的静态方法 static CProcessXmlConfigFile& instance(const string& xmlfile); //|=======================================| //| 以下为设置xml文件的各方法 | //|=======================================| /*获取面板对象名称列表*/ void getPanListInfo(void); /*获取指定面板下的树列表*/ void getTreeInfoOfPan(PanIndex _index); /*返回面板对象列表*/ inline panNames_t getPanList(void) const { return m_panobj; } /*返回当前面板下的树列表对象*/ inline ptree_nodes_t getPtreeNodeList(void) const { return m_ptreeobj; } private: CProcessXmlConfigFile(const string& xmlfile); CProcessXmlConfigFile(const CProcessXmlConfigFile&); CProcessXmlConfigFile& operator=(const CProcessXmlConfigFile&); /************************************************************************/ /* 以下为内部功能方法 */ /************************************************************************/ //合理性验证方法[_index:面板索引] bool ICanWork(PanIndex _index); //加载文件[xml文件名<含路径>] bool loadfile(const string& xmlfile); //递归遍历节点目录树函数[nodepath:节点路径<分割符为'/'>] void recursive_print(const string& nodepath); private: xmlParser m_parser; //xml文件解析对象 panNames_t m_panobj;//存储面板对象列表 //存储当前面板下的树节点对象列表 ptree_nodes_t m_ptreeobj; }; //CProcessXmlConfigFile.cpp #i nclude "StdAfx.h" #i nclude "ProcessXmlConfigFile.h" #i nclude <iostream> // #i nclude <boost/foreach.hpp> #i nclude <boost/format.hpp> #i nclude <boost/typeof/typeof.hpp> #i nclude <boost/make_shared.hpp> // #i nclude <boost/ref.hpp> // #i nclude <boost/program_options/detail/convert.hpp> // #i nclude <boost/program_options/detail/utf8_codecvt_facet.hpp> // #i nclude <windows.h> // #i nclude <stdlib.h> using namespace std; using namespace boost; //参数默认值.. const int iDefaultInt = 0; const string strNullString = ""; const char chflag = '/'; const string strPan = "doc/pans/pan"; const string strflag = "<xmlattr>"; const wstring win32_dir_splitchar = L"\\"; ////////////////////////////////////////////////////////////////////////// CProcessXmlConfig:CProcessXmlConfigFile(const string& xmlfile) { loadfile(xmlfile); m_panobj.clear(); m_panobj.reserve(MAX_PANLIST_NUM); } CProcessXmlConfig:~CProcessXmlConfigFile(void) { } CProcessXmlConfigFile& CProcessXmlConfig:instance(const string& xmlfile) { static CProcessXmlConfigFile _instance(xmlfile); return _instance; } void CProcessXmlConfig:getPanListInfo( void ) { //开始获取. //首先获取总面板节点个数 assert(m_parser.get_optional<int>("doc.pans.<xmlattr>.glcount")); //循环获取各节点名称 string str = ""; auto_t(child, m_parser.get_child("doc.pans")); for (auto_t(t, child.begin()); t != child.end(); ++t) { str = t->first; if (str.find("pan") == string::npos)continue; m_panobj.push_back(t->second.data()); } } void CProcessXmlConfig:getTreeInfoOfPan( PanIndex _index ) { //防御性设计 if (!ICanWork(_index))return; //.. format fmt("%s-%d"); fmt % strPan % _index; m_ptreeobj.clear(); recursive_print(fmt.str()); } bool CProcessXmlConfig:ICanWork( PanIndex _index ) { return (_index >= ST_PhysicalCharacteristics && _index <= ST_Report); } bool CProcessXmlConfig:loadfile(const string& xmlfile) { //防御性设计 if (xmlfile.empty())return false; //.. try { //获取当前应用程序路径.. wstring strPath(L""); { TCHAR currPath[MAX_FNAME_LEN+1] = {0}; GetModuleFileName(NULL, currPath, MAX_FNAME_LEN); TCHAR *psz = _tcsrchr(currPath, '\\'); if (psz) { *psz = '\0'; //取出程序所在的目录 lstrcat(currPath, win32_dir_splitchar.c_str()); strPath = currPath; } } //加载配置文件. string xmlfilePath = WideToASCII(strPath.c_str()) + xmlfile; // std::locale oldLocale; // std::locale utf8Locale(oldLocale, // new boost::program_options::detail::utf8_codecvt_facet()); read_xml(xmlfilePath, m_parser, xml_parser::no_comments); } catch(std::exception& e) { AfxMessageBox(ASCIIToWide(e.what()).c_str()); return false; } return true; } //递归遍历xml节点目录树函数.. void CProcessXmlConfig:recursive_print( const string& nodepath ) { if (nodepath.empty())return; static size_t nproc = 0; //记录递归层次[测试留用] //.. string strKey, strKey_, str; auto_t(node, m_parser.get_child(ptree::path_type(nodepath, chflag))); //获取节点信息 for (auto_t(pt, node.begin()); pt != node.end(); ++pt) { strKey = pt->first; if (strKey.find(strflag) != string::npos) continue; str = pt->second.data(); // for (size_t i = 0; i < nproc; ++i) // cout << "\t"; // cout << strKey << " = " << (str.empty() ? "empty" : str); ////////////////////////////////////////////////////////////////////////// strKey_ = nodepath + "/" + strKey + "/" + strflag; auto_t(attr, m_parser.get_child(ptree::path_type(strKey_, chflag))); //获取节点属性信息 for (auto_t(tt, attr.begin()); tt != attr.end(); ++tt) { string atkey = tt->first; size_t atnval = tt->second.get_<int>(); m_ptreeobj.push_back(make_tuple(sh_pstr(new string(strKey)), atnval, sh_pstr(str.empty() ? new string("empty") : new string(str)))); // cout << " <" << atkey << ":" << atnval << ">" << endl; strKey = nodepath + "/" + pt->first; if (atnval > 0) //若子节点数目不止一个则递归遍历 { ++nproc; recursive_print(strKey); } } } --nproc; // cout << "*****************************************\n"; } //主程序文档类中用到了CViewTree来动态加载节点,具体调用如下: instance = &CProcessXmlConfig:instance(xmlfile); BOOST_ASSERT(instance); //获取面板名称列表. instance->getPanListInfo(); szPanName = instance->getPanList(); if (szPanName.empty())return; // BOOST_FOREACH(panNames_t::_type& p, szPanName) // AfxMessageBox(CString(p.c_str())); for (size_t i = 0; i < szPanName.size(); ++i) { // 首先生成树 CViewTree * ptree = new CViewTree; if (!ptree)return; //...... FillClassView(); //...... } FillClassView()方法主体如下: { //防御性设计 if (m_objtree.empty())return; if (m_nindex < 0 || m_nindex >= m_objtree.size())return; shared_wnd_ptr pTreeView = m_objtree[m_nindex]; if (NULL == pTreeView)return; ////////////////////////////////////////////////////////////////////////// //加载配置文件并读取配置数据.. { //获取当前面板树节点集合信息. BOOST_ASSERT(instance); instance->getTreeInfoOfPan(m_pIndex); ptree_nodes_t ptreenodes = instance->getPtreeNodeList(); if (ptreenodes.empty())return ; //动态生成树节点.. { int nsub = 0; HTREEITEM item, pitem; std::stack<HTREEITEM> S; S.push(pitem); BOOST_FOREACH(node_t& node, ptreenodes) { size_t n = node.get<1>(); string strVal = *node.get<2>(); if (strVal.empty() || !strVal.compare("empty"))continue; if (nsub > 0) { pitem = S.empty() ? NULL : S.top(); item = pTreeView->InsertItem(CString(strVal.c_str()), pitem); } else { if (!S.empty()) S.pop(); pitem = S.empty() ? NULL : S.top(); item = pTreeView->InsertItem(CString(strVal.c_str()), pitem); } if (0 == n) --nsub; else { nsub = n; S.push(item); } } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |