JSON的c/c++实现版本很多,可是用起来总是感觉不是那么顺手,于是就把自己能用的所谓奇技淫巧全都使了出来,可是貌似还是不尽满意。不过还是贴出来,算是当个纪念吧。
#include <unordered_map>
#include <algorithm>
#include <sstream>
#include <vector>
#include <map>
typedef std::unordered_map<std::string,std::string> object_container;
namespace value_object_detail{
static const std::string string_type = "string";
static const std::string number_type = "number";
static const std::string bool_type = "bool";
static const std::string object_type = "object";
static const std::string array_type = "array";
static const std::string null_type = "null";
JSON数值实现类,用来尽可能的使得字符串数值和c/c++原生数据类型无缝集成
class json_value{
public:
json_value(object_container& inst,const std::string& key):
inst_(inst),preffix_(key)
{
}
json_value(const json_value& jv):inst_(jv.inst_),preffix_(jv.preffix_){
}
protected:
void set_meta_information(const std::string& key,int index = 0){
std::string& key_type = inst_[preffix_];
const char* assert_type = NULL;
std::stringstream ss;
if(!key.empty()){
ss << "object@" << key << ",";
assert_type = "array@";
}else{
ss << "array@" << index << ",";
assert_type = "object@";
}
std::string append_type = ss.str();
if(std::string::npos != key_type.find(assert_type)){
del();
inst_[preffix_] = append_type;
return;
}
//assign repeat
if(std::string::npos == key_type.find(append_type)){
key_type += append_type;
}
}
public:
json_value operator[](int i){
using namespace value_object_detail;
set_meta_information("",i);
std::stringstream ss;
ss << preffix_ << "." << i;
return json_value(inst_,ss.str());
}
json_value operator[](const std::string& key){
using namespace value_object_detail;
set_meta_information(key);
return json_value(inst_,key.empty() ? preffix_ : preffix_ + "." + key);
}
public:
std::string& operator*(){
return inst_[preffix_];
}
bool operator!()const{
return inst_.end() == inst_.find(preffix_);
}
public:
const std::string& str_value()const {
const static std::string ret;
object_container::const_iterator it = inst_.find(preffix_);
return inst_.end() == it ? ret : it->second;
}
const std::string& str_key()const {
return preffix_;
}
public:
const std::string& type_string()const{
const std::string& val = str_value();
if(val.empty()){
return null_type;
}
if(std::string::npos != val.find("array@")){
return array_type;
}
if(std::string::npos != val.find("object@")){
return object_type;
}
return number_type;
}
public:
template<class Fn>
void for_each(Fn f){
object_container::const_iterator it = inst_.find(preffix_);
const std::string& type = type_string();
if(inst_.end() == it || (array_type != type && object_type != type)){
return ;
}
std::string sub_key = "";
std::string::size_type posb = 0,pose = 0,posn = std::string::npos;
object_container::const_iterator sub_it;
for(posb = pose = 0;;posb += 1,pose += 1){
posb = it->second.find('@',posb);
pose = it->second.find(',',pose);
if(posn == posb || posn == pose){
break;
}
sub_key = it->second.substr(posb+1,pose - posb -1);
sub_it = inst_.find(preffix_ + "." + sub_key);
if(inst_.end() != sub_it){
f(sub_key,sub_it->second);
}else{
f(sub_key,"");
}
}
}
void del(){
const std::string& type = type_string();
if(array_type == type){
int i = 0;
for(json_value jv = this->operator[](i);!!jv;++i){
jv.del();
}
}else if(object_type == type){
for_each([this](const std::string& key,const std::string& v){
json_value sub_item = this->operator[](key);
sub_item.del();
});
}
inst_.erase(preffix_);
}
public:
template<class T>
json_value& operator=(const T& val){
*this << val;
return *this;
}
json_value& operator=(const std::string& val){
inst_[preffix_] = val;
return *this;
}
json_value& operator=(const json_value& jv){
inst_ = jv.inst_;
preffix_ = jv.preffix_;
return *this;
}
private:
object_container& inst_;
std::string preffix_;
};
各种赋值包装
template<class T>
json_value& operator <<(json_value& jv,const T& val){
std::stringstream ss;
ss << val;
*jv = ss.str();
return jv;
}
template<class T>
json_value& operator <<(json_value& jv,const bool& val){
*jv = val ? "true" : "false";
return jv;
}
template <class T>
json_value& operator<<(json_value& jv,const std::vector<T>& val){
int i = 0;
std::for_each(val.begin(),val.end(),[&i,&jv](const T& v){
jv[i++] = v;
});
return jv;
}
template <class T, int N>
json_value& operator<<(json_value& jv,const T (&val)[N]){
int i = 0;
std::for_each(&val[0],&val[N],[&i,&jv](const T& v){
jv[i++] = v;
});
return jv;
}
template<class T>
json_value& operator>>(json_value& jv,T& val){
std::stringstream ss;
ss << *jv;
ss >> val;
return jv;
}
template<>
json_value& operator>>(json_value& jv,bool& val){
val = ("true" == *jv);
return jv;
}
template<>
json_value& operator>>(json_value& jv,std::string& val){
val = *jv;
return jv;
}
template <class T>
json_value& operator>>(json_value& jv,std::vector<T>& val){
int i = 0;
jv.for_each([&val,&jv,&i](const std::string& k,const std::string&v){
T t;
jv[i++] >> t;
val.push_back(t);
});
return jv;
}
template <class T, int N>
json_value& operator>>(json_value& jv,T (&val)[N]){
int i = 0;
jv.for_each([&val,&jv,&i](const std::string& k,const std::string&v){
jv[i] >> val[i];
++i;
});
return jv;
}
一个简单的JSON解析器,没有语法检测,而且效率还不敢恭维,实在有重构的必要
class json_parser{
public:
json_parser(json_value& value):values_(value){
}
protected:
json_value values_;
std::list<std::string> items_;
public:
bool operator()(const std::string& json_str){
state_ op(items_);
std::for_each(json_str.begin(),json_str.end(),op);
parse_items();
return items_.empty();
}
bool operator()(std::istream& is){
state_ op(items_);
std::for_each(std::istream_iterator<char>(is),std::istream_iterator<char>(),op);
parse_items();
return items_.empty();
}
protected:
void parse_items(){
if("{" != items_.front() && "[" != items_.front()){
items_.push_front("{");
items_.push_back("}");
}
parse_object(values_);
}
protected:
class state_{
private:
bool in_close_;
std::string item_;
std::list<std::string>& items_;
protected:
bool in_string(const char& c){
if(!in_close_){
return false;
}
if('"' == c && '\\' != item_.back()){
in_close_ = false;
return false;
}
if(item_.empty() || '\\' != item_.back()){
item_.push_back(c);
return true;
}
switch(c){
case '"': item_.back() = '"'; break;
case 't': item_.back() = '\t'; break;
case 'n': item_.back() = '\n'; break;
case 'r': item_.back() = '\r'; break;
case '\\': item_.back() = '\\'; break;
default: item_.push_back(c);break;
}
return true;
}
public:
state_(std::list<std::string>& items):in_close_(false),items_(items){}
public:
void operator()(const char& c){
if(in_string(c)){
return;
}
switch (c)
{
case '"': {
if(!in_close_ && !item_.empty()){
items_.push_back(item_);
item_.clear();
break;
}
in_close_ = item_.empty();
break;
}
case '{': case '}': case '[': case ']':{
item_.push_back(c);
items_.push_back(item_);
item_.clear();
break;
}
case ':': case ',':{
item_.empty() ? (void) 0 : items_.push_back(item_);
item_.clear();
break;
}
case ' ': case '\t': case '\n': case '\r':{
break;
}
default:{
item_.push_back(c);
break;
}
}
}
};
protected:
void parse_object(json_value& jv){
if("{" != items_.front()){
return;
}
for(items_.pop_front();"}" != items_.front();){
parse_item(jv);
}
items_.pop_front();
}
void set_item_value(json_value& jv){
std::string val = items_.front();
if(val == "["){
parse_array(jv);
return;
}
if(val == "{"){
parse_object(jv);
return;
}
*jv = val;
items_.pop_front();
}
void parse_array(json_value& jv){
if("[" != items_.front()){
return;
}
int i = 0;
for(items_.pop_front();"]" != items_.front(); ++i){
set_item_value(jv[i]);
}
items_.pop_front();
}
void parse_item(json_value& jv){
std::string key = items_.front();
items_.pop_front();
set_item_value(jv[key]);
}
};
一个JSON字符串生成器,同样不是很严格
class json_maker {
public:
json_maker(std::ostream& os,json_value& jv):os_(os),json_vlaue_(jv){
}
protected:
std::ostream& os_;
json_value& json_vlaue_;
public:
void operator()(){
os_ << "{";
json_vlaue_.for_each([this](const std::string& k,const std::string& v){
this->to_string(this->json_vlaue_[k]);
this->os_ << ",";
});
#define set_last_op(c) do{\
std::ostream::off_type pos = os_.tellp();\
os_.seekp(pos -1);\
os_.write(c,1);\
}while(0)
set_last_op("}");
}
protected:
void to_string(json_value& item,bool array_item = false){
const std::string& type = item.type_string();
if(!array_item){
const std::string& preffix_ = item.str_key();
std::string::size_type pos = preffix_.find_last_of('.');
std::string key = (std::string::npos == pos) ? preffix_ : preffix_.substr(pos + 1);
os_ << "\"" << key << "\":";
}
if(array_type == type){
os_ << "[";
int i = 0;
for(json_value jv = item[i];!!jv; jv = item[++i]){
to_string(jv,true);
os_ << ",";
}
set_last_op("]");
}else if(object_type == type){
os_ << "{";
item.for_each([this,&item](const std::string& k,const std::string& v){
to_string(item[k]);
this->os_ << ",";
});
set_last_op("}");
}else{
formart_value(item.str_value());
}
}
#undef set_last_op
protected:
bool isnumber(const std::string& str)const{
for(const char* cstr = str.c_str();*cstr;++cstr){
switch (*cstr)
{
case '+': case '-': case '.':
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': case 'e': case 'E':
{
break;
}
default:
return false;
break;
}
}
return true;
}
protected:
void formart_value(const std::string& val){
if(val.empty()){
os_ << "\"\"";
return;
}
if("true" == val || "false" == val || isnumber(val)){
os_ << val;
return ;
}
os_ << "\"";
std::for_each(val.begin(),val.end(),[this](const char& c){
switch (c)
{
case '"': this->os_ << "\\\""; break;
case '\t': this->os_ << "\\t"; break;
case '\n': this->os_ << "\\n"; break;
case '\r': this->os_ << "\\r"; break;
case '\\': this->os_ << "\\\\"; break;
default:{
this->os_ << c;
break;
}
}
});
os_ << "\"";
}
};
}//end namespace
下面是正JSON使用类的一个包装
class value_object {
protected:
object_container values_;
public:
value_object(){}
value_object(const std::string& json_str){parse_string(json_str);}
private:
typedef value_object_detail::json_value json_value;
public:
template<class T>
value_object& operator()(const std::string& key,const T& value){
using namespace value_object_detail;
json_value(values_,"root." + key) << value;
return *this;
}
template<class T>
value_object& operator()(const std::string& key,T& value,bool& exist){
using namespace value_object_detail;
json_value jv(values_,"root." + key);
exist = !!jv;
if(exist) jv >> value ;
return *this;
}
public:
json_value operator[](const std::string& key){
return json_value(values_,"root")[key];
}
json_value operator[](int i){
return json_value(values_,"root")[i];
}
public:
bool operator==(const value_object& vo)const{
if(this == &vo){
return true;
}
if(vo.values_.size() != values_.size()){
return false;
}
bool result = true;
std::for_each(vo.values_.begin(),vo.values_.end(),[this,&result](const object_container::const_reference cr){
if(!result){
return;
}
if(std::string::npos != cr.second.find("object@")){
return;
}
if(std::string::npos != cr.second.find("array@")){
return;
}
object_container::const_iterator it = this->values_.find(cr.first);
result = (it != this->values_.end()) && (it->second == cr.second);
});
return result;
}
public:
std::ostream& to_string(std::ostream& os){
using namespace value_object_detail;
json_maker(os,json_value(values_,"root"))();
return os;
}
void parse_string(const std::string& json_str){
using namespace value_object_detail;
json_parser jp(json_value(values_,"root"));
jp(json_str);
}
};
测试程序
#include <iostream>
#include <string>
#include <vector>
struct test_json_obj{
int ta;
double tb;
std::string ts;
public:
bool operator==(const test_json_obj& r)const{
return ta == r.ta && int(tb * 1000) == int(r.tb * 1000) && ts == r.ts;
}
};
std::ostream& operator<<(std::ostream& os,const test_json_obj& jo){
os << "{\nta:" << jo.ta << ",\ntb:" << jo.tb << ",\nts:\"" << jo.ts << "\"\n}\n";
return os;
}
namespace value_object_detail{
json_value& operator<<(json_value& vc,const test_json_obj& val){
vc["ta"] = val.ta;
vc["tb"] = val.tb;
vc["ts"] = val.ts;
return vc;
}
json_value& operator>>(json_value& vc, test_json_obj& tj){
vc["ta"] >> tj.ta;
vc["tb"] >> tj.tb;
vc["ts"] >> tj.ts;
return vc;
}
}
int main(int argn,char* argv[]){
value_object vo;
bool exist,null_value;
{
test_json_obj obj = {
1,6.248f,"haha, object"
},obj1 = {0,0.0f,""},obj2;
test_json_obj obj_array1[] = {
obj,obj1
},obj_array2[3];
std::vector<test_json_obj> v1,v2;
v1.push_back(obj);
v1.push_back(obj1);
vo["aa"] = 1;
vo("v1",obj)("array" ,obj_array1)("vector" ,v1);
vo("v1",obj1,exist)("array",obj_array2,exist)("vector" ,v2,exist)("v2",obj2,null_value);
assert( exist || !null_value);
assert(obj1 == obj);
assert(v2 == v1);
for(int i = 0; i < 2; ++i){
assert(obj_array1[i] == obj_array2[i]);
}
vo["v1"] = v1;
v2.clear();
vo["v1"] >> v2;
assert(v1 == v2);
std::for_each(v2.begin(),v2.end(),[](const test_json_obj& v){std::cout << v << ",";});
vo["obj_array"] = obj_array1;
vo["obj_array"] >> obj_array2;
for(int i = 0; i < 2; ++i){
assert(obj_array1[i] == obj_array2[i]);
}
int int_array1[] = { 1,2,3,4,5,6,7},int_array2[10] = {0};
vo["int_array"] = int_array1;
vo["int_array"] >> int_array2;
for(int i = 0; i < 7; ++i){
assert(int_array1[i] == int_array2[i]);
}
vo["int"] = 0;
vo["double"] = 3.1425f;
vo["string"] = std::string("hi test");
int a;double b; std::string s;
vo("int",a,exist)("double",b,exist)("string",s,exist);
assert(a == 0 && int(31425) == int(b * 10000) && s == "hi test");
vo["obj1"] = obj;
vo["obj1"] >> obj1;
assert(obj == obj1);
std::cout << "old_obj = " << obj1 << std::endl;
vo["obj1.ta"] = 2;
vo["obj1.tb"] = 3.1415f;
vo["obj1.ts"] = std::string("hi test");
vo["obj1"] >> obj;
assert(obj.ta == 2 && int(obj.tb * 1000) == int(3141) && obj.ts == "hi test");
std::cout << "new_obj = " << obj;
}
{
const char* json_str = "{"\
"a:1,"\
"\"b \" :2,"\
"c : \"asdf\\\"asdf\","\
"ab : [1,2,3,4,\"asdfasdf\"],"\
"ao : [{"\
"a:1,"\
"b:2,"\
"c:\"asdf\""\
"}]"\
"}";
vo.parse_string(json_str);
int a, b;
std::string c;
vo("a",a,exist)("b ",b,exist)("c",c,exist);
assert(a == 1 && b == 2 && c == "asdf\"asdf");
vo["ab"][0] >> b;
vo["ab"][1] >> a;
vo["ab"][4] >> c;
assert(a == 2 && b == 1 && c == "asdfasdf");
vo["ao"][0]["a"] >> a;
vo["ao"][0]["b"] >> b;
vo["ao"][0]["c"] >> c;
assert(a == 1 && b == 2 && c == "asdf");
std::stringstream ss;
vo.to_string(ss) << std::endl;
std::cout << ss.str() << std::endl;
}
{
const char* json_str = "{"\
"a:1,"\
"\"b \" :2,"\
"c : \"asdf\\\"asdf\","\
"ab : [1,2,3,4,\"asdfasdf\"],"\
"ao : [{"\
"a:1,"\
"b:2,"\
"c:\"asdf\""\
"}]"\
"}";
value_object vo1;
std::stringstream ss;
vo1.parse_string(json_str);
vo1.to_string(ss);
value_object vo2;
vo2.parse_string(ss.str());
assert(vo1 == vo2);
}
return 0;
}
测试结果
{
ta:1,
tb:6.248,
ts:"haha, object"
}
,{
ta:0,
tb:0,
ts:""
}
,old_obj = {
ta:1,
tb:6.248,
ts:"haha, object"
}
new_obj = {
ta:2,
tb:3.1415,
ts:"hi test"
}
{"aa":1,"v1":[{"ta":1,"tb":6.248,"ts":"haha, object"},{"ta":0,"tb":0,"ts":""}],"obj_array":[{"ta":1,"tb":6.248,"ts":"haha, object"},{"ta":0,"tb":0,"ts":
""}],"int_array":[1,2,3,4,5,6,7],"int":0,"double":3.1425,"string":"hi test","obj1":{"ta":2,"tb":3.1415,"ts":"hi test"},"ta":2,"tb":3.1415,"ts":"hi test"
,"a":1,"b ":2,"c":"asdf\"asdf","ab":[1,2,3,4,"asdfasdf"],"ao":[{"a":1,"b":2,"c":"asdf"}]}