SpartacusIn21

专注:c++,python,d3d,设计模式,人工智能,并行计算

jsoncpp动态解析节点类型

   在互联网无处不在的今天,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数据类型的目的。

 

posted on 2017-07-06 16:29  SpartacusIn21  阅读(2797)  评论(0编辑  收藏  举报

导航