在互聯網無處不在的今天,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數據類型的目的。

