在互联网无处不在的今天,JSON作为轻量级数据存储格式,被广泛应用到互联网数据传输中。众所周知,JSON由键/值对、对象、数组组成,其中键/值对的值包括以下几种类型:
enum ValueType { nullValue = 0, ///< 'null' value intValue, ///< signed integer value uintValue, ///< unsigned integer value realValue, ///< double value stringValue, ///< UTF-8 string value booleanValue, ///< bool value arrayValue, ///< array value (ordered list) objectValue ///< object value (collection of name/value pairs). };
如果在发送方和接收方间约定JSON数据格式中数据类型固定不变,那么不存在需要动态去判断节点数据类型并解析的问题。但是在实际应用过程中,存在两种情况需要支持JSON数据类型动态解析:第一,发送方因为平台迁移等种种原因导致的数据类型变化,比如本来为"key":200的键值对变成了"key":"200",这个时候如果还是按照intValue去获取key的值的话,就会解析失败; 第二,接收方不愿意一个个去按照数据类型去解析JSON数据的时候,想动态去获取数据,比如"key":20,按照stringValue和intValue都能正确的解析。
针对以上情况,本文基于jsoncpp设计了一个动态解析JSON数据的类,主要包括两个函数:
DynamicGetValue:支持解析int,uint,double,bool以及前三种类型的stringValue形式,当遇到"key":"1.23"键值对后,该函数就会进入Json::stringValue语句,通过atof函数保持了数据的精度
DynamicGetStrValue:支持解析stringValue类型以及DynamicGetValue函数支持的数据类型,在调用DynamicGetValue模板函数时,是使用的double实例化,目的是为了保证不丢失数据精度
template<typename T> bool DynamicGetValue(Json::Value &value, T &&sValue){ //获取json int、uint、bool、double类型的值的值 bool result = true; switch(value.type()){ case Json::stringValue: sValue = atof(value.asString().c_str()); break; case Json::int64Value: sValue = value.asInt(); break; case Json::uint64Value: sValue = value.asUInt(); break; case Json::booleanValue: sValue = value.asBool(); break; case Json::realValue: sValue = value.asDouble(); break; default: result = false; break; } return result; }
bool DynamicGetStrValue(Json::Value &value,string &sValue){ //获取json string、int、uint、bool、double的值 bool result = true; double nValue = -1; if(value.type() == Json::stringValue){ sValue = value.asString(); } else if(DynamicGetValue<double&>(value, nValue)){ sprintf((char*)sValue.data(),"%.8f", nValue); } else{ result = false; } return result;
}
针对上动态数据类型解析函数,设计了如下测试试用例,这里我们把strJson数据中的"data1":1,"data2":3.1415927两个键值对当做stringValue类型来解析,能够正确的获取数据。但是切记,不能将"msg"和"code"调用DynamicGetValue解析,因为它们只能用stringValue来表达,只能调用DynamicGetStrValue解析,所以这里DynamicGetStrValue是万能的,能解析任何类型的数据。
int main(){ string strJson = "{\"msg\":\"正常\", \"code\":\"A0000\", \"data1\":1,\"data2\":3.1415927, \"data3\":-4}"; Json::Reader reader; Json::Value root; Json::Value value; if (!reader.parse(strJson, root, false)) { return; } string msg_,code_,strValue1,strValue2; unsigned int data1; double data2; int data3; if(root.isMember("msg")){ value = root["msg"]; DynamicGetStrValue(value,msg_); } if(root.isMember("code")){ value = root["code"]; DynamicGetStrValue(value,code_); } if(root.isMember("data1")){ value = root["data1"]; DynamicGetValue(value,data1); } if(root.isMember("data2")){ value = root["data2"]; DynamicGetStrValue(value,strValue1); } if(root.isMember("data3")){ value = root["data3"]; DynamicGetStrValue(value, strValue2); } char strVal[100]={0} ; sprintf(strVal,"%s, %s, %d, %s, %s", msg_.c_str(), code_.c_str(), data1, strValue1.c_str(), strValue2.c_str()); return 1; }
上测试用例输出如下图,正确的获取了data1和data2的值,达到了动态解析JSON数据类型的目的。