boost.propertytree是boost一个用于格式文本读写的库,可以读写XML、json之类的,这个库不需要编译,直接引入它的头文件就可以了。我用它的ptree写了一个读写XML配置文件的类,因为它本身的写XML格式有点问题,所以写文件部分重写了一下。
MVXMLConfig.h
#ifndef _MVXMLCONFIG_H_
#define _MVXMLCONFIG_H_
#define BOOST_SPIRIT_THREADSAFE
#include <string>
#include <exception>
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
using namespace std;
using namespace boost::property_tree;
class CMVXMLConfig
{
public:
CMVXMLConfig();
~CMVXMLConfig();
void open(const string &file_path);
void save();
void show(const string& path="");
string get_string(const string &key);
void set_string(const string &key, const string &val);
int get_int(const string &key);
void set_int(const string &key, const int val);
bool get_boolean(const string &key);
void set_boolean(const string &key, const bool val);
double get_float(const string &key);
void set_float(const string &key, const double val);
string get_attribute_string(const string &key, const string &subkey);
void set_attribute_string(const string &key, const string &subkey, const string &val);
int get_attribute_int(const string &key, const string &subkey);
void set_attribute_int(const string &key, const string &subkey, const int val);
bool get_attribute_boolean(const string &key, const string &subkey);
void set_attribute_boolean(const string &key, const string &subkey, const bool val);
double get_attribute_float(const string &key, const string &subkey);
void set_attribute_float(const string &key, const string &subkey, const double val);
protected:
string xmlpath;
ptree xmltree;
};
template <class T>
void set_value(ptree &pt,const string &key,const T &val)
{
try
{
pt.put(key,val);
}
catch (...)
{
cout<<"set_value() throw exception"<<endl;
}
}
template <class T>
T& get_value(T &val,ptree &pt,const string &key,const T &default_value)
{
val = default_value;
try
{
val = pt.get<T>(key);
}
catch (...)
{
cout<<"get_value() throw exception"<<endl;
}
return val;
}
template <class T>
T& get_attribute_value(T &val,ptree &pt,const string &key,const string &subkey,const T &default_value)
{
val = default_value;
try
{
BOOST_FOREACH(ptree::value_type &sub, pt.get_child(key))
{
if (sub.first=="<xmlattr>")
{
val = sub.second.get<T>(subkey);
break;
}
}
}
catch (...)
{
cout<<"get_attribute_value() throw exception"<<endl;
}
return val;
}
template <class T>
void set_attribute_value(ptree &pt,const string &key,const string &subkey,const T &val)
{
try
{
string attr = "<xmlattr>."+subkey;
BOOST_FOREACH(ptree::value_type &sub, pt.get_child(key))
{
if (sub.first=="<xmlattr>")
{
sub.second.put(attr,val);
break;
}
}
}
catch (...)
{
}
}
void build_tree(stringstream &outstream, ptree &root, int curLayer);
#endif// _MVXMLCONFIG_H_
MVXMLConfig.cpp
#include "MVXMLConfig.h"
#include "boost/program_options/detail/utf8_codecvt_facet.hpp"
CMVXMLConfig::CMVXMLConfig()
{
}
CMVXMLConfig::~CMVXMLConfig()
{
save();
}
void CMVXMLConfig::open(const string &file_path)
{
try
{
if (xmlpath.size()>0)
{
xml_parser::write_xml(xmlpath,xmltree);
xmltree.clear();
}
xmlpath = file_path;
xml_parser::read_xml(xmlpath,xmltree);
}
catch(...)
{
cout<<"file: "<<xmlpath<<endl
<<"CMVXMLConfig::open() throw exception"<<endl;
}
}
void CMVXMLConfig::save()
{
try
{
ofstream out(xmlpath.c_str(),ios::out);
if (out)
{
//格式化输出,指定编码(默认utf-8)
//boost::property_tree::xml_writer_settings<char> settings('\t', 1, "UTF-8");
//write_xml(xmlpath, xmltree, std::locale(), settings);
stringstream stream;
//std::locale oldLocale;
//std::locale utf8Locale(oldLocale,new boost::program_options::detail::utf8_codecvt_facet());
//stream.imbue(utf8Locale);
stream<<"<?xml version=\"1.0\" encoding=\"utf-8\"?>"<<endl;
build_tree(stream,xmltree,0);
out<<stream.str()<<endl;
out.close();
}
else
{
cout<<"file: "<<xmlpath<<"open failed"<<endl;
}
}
catch (...)
{
cout<<"file: "<<xmlpath<<endl
<<"CMVXMLConfig::save() throw exception"<<endl;
}
}
void CMVXMLConfig::show(const string& path)
{
try
{
stringstream stream;
build_tree(stream,xmltree.get_child(path),0);
// That mean this node without child, print its' value
if(stream.str().size()==0)
cout<<get_string(path)<<endl;
else
cout<<stream.str()<<endl;
}
catch(...)
{
cout<<"CMVXMLConfig::show() throw exception"<<endl;
}
}
string CMVXMLConfig::get_string(const string &key)
{
string val;
return get_value(val,xmltree,key,string(""));
}
void CMVXMLConfig::set_string(const string &key, const string &val)
{
set_value(xmltree,key,val);
save();
}
int CMVXMLConfig::get_int(const string &key)
{
int val;
return get_value(val,xmltree,key,0);
}
void CMVXMLConfig::set_int(const string &key, const int val)
{
set_value(xmltree,key,val);
save();
}
bool CMVXMLConfig::get_boolean(const string &key)
{
bool val;
return get_value(val,xmltree,key,false);
}
void CMVXMLConfig::set_boolean(const string &key, const bool val)
{
set_value(xmltree,key,val);
save();
}
double CMVXMLConfig::get_float(const string &key)
{
string val = get_string(key);
return atof(val.c_str());
}
void CMVXMLConfig::set_float(const string &key, const double val)
{
set_value(xmltree,key,val);
save();
}
// attibute
string CMVXMLConfig::get_attribute_string(const string &key, const string &subkey)
{
string val;
return get_attribute_value(val,xmltree,key,subkey,string(""));
}
void CMVXMLConfig::set_attribute_string(const string &key, const string &subkey, const string &val)
{
set_attribute_value(xmltree,key,subkey,val);
save();
}
int CMVXMLConfig::get_attribute_int(const string &key, const string &subkey)
{
int val;
return get_attribute_value(val,xmltree,key,subkey,0);
}
void CMVXMLConfig::set_attribute_int(const string &key, const string &subkey, const int val)
{
set_attribute_value(xmltree,key,subkey,val);
save();
}
bool CMVXMLConfig::get_attribute_boolean(const string &key, const string &subkey)
{
bool val;
return get_attribute_value(val,xmltree,key,subkey,false);
}
void CMVXMLConfig::set_attribute_boolean(const string &key, const string &subkey, const bool val)
{
set_attribute_value(xmltree,key,subkey,val);
save();
}
double CMVXMLConfig::get_attribute_float(const string &key, const string &subkey)
{
string val;
get_attribute_string(key,subkey);
return atof(val.c_str());
}
void CMVXMLConfig::set_attribute_float(const string &key, const string &subkey, const double val)
{
set_attribute_value(xmltree,key,subkey,val);
save();
}
void build_tree(stringstream &outstream, ptree &root, int curLayer)
{
BOOST_FOREACH(ptree::value_type &v1, root)
{
if (v1.second.empty())
{
int layer = curLayer;
while (layer--)
{
outstream<<'\t';
}
outstream<<"<"<<v1.first<<">"<<v1.second.data()<<"</"<<v1.first<<">"<<endl;
}
else
{
bool isAttr = false;
// 先看看子节点是否是属性
BOOST_FOREACH(ptree::value_type &vAttr, v1.second)
{
if (vAttr.first == "<xmlattr>")
{
isAttr = true;
break;
}
}
if (v1.first == "<xmlattr>")
{
BOOST_FOREACH(ptree::value_type &vAttr, v1.second)
{
outstream<<" "<<vAttr.first<<"=\""<<vAttr.second.data()<<"\"";
}
outstream<<">"<<endl;
}
else
{
if (isAttr)
{
int layer = curLayer;
while (layer--)
{
outstream<<'\t';
}
outstream<<"<"<<v1.first;
}
else
{
int layer = curLayer;
while (layer--)
{
outstream<<'\t';
}
outstream<<"<"<<v1.first<<">"<<endl;
}
build_tree(outstream,v1.second,curLayer+1);
{
int layer = curLayer;
while (layer--)
{
outstream<<'\t';
}
outstream<<"</"<<v1.first<<">"<<endl;
}
}
}
}
}