菜鸟笔记
提升您的技术认知

如何用json::value和json::reader分析json格式的数据-ag真人游戏

jsoncpp 是一个用来处理 json文本的开源c 库,最近需要分析服务器的json格式数据,所以,学习了一下。下面就简单介绍使用jsoncpp的json::reader和json::value来分析数据。

json::value操作有点像数组,先回忆下c/c 里的数组。

数组的定义是内存存储类型相同的连续的内存空间,其定义方式如下:

数组类型名 数组名[元素个数];

以上是一维数组,二维数组可看作是每个元素都是一个一维数组的一维数组,其定义如下:

数组类型名  数组名[元素分组个数][每组元素个数];

比如初始化一个一维数组:

char name[8] = "your name";

此时,name不足以容纳字符串”your name“,最后一个字符e会舍弃

而当你在name里存储三个名字时,就需要这样定义它:

char* name2[3] = {"your name","my name","his name"};

printf("%s|%s|%s\n",name2[0],name2[1],name2[2]);

输出:

your name|my name|his name

这样的话,相当于每个元素是char*,一共有三个元素。这不是一维数组,怎么说是二维的呢?

这样写就看得清楚了:

char name3[3][5] = {"name1","name2","name3"};

然后用输出

printf("%s|%s|%s\n",name3[0],name3[1],name3[2]);

结果是

name1name2name3l@|name2name3l@|name3l@

和预想的不同。为什么呢?

因为字符串是以 '\0'结尾的,所以"name1"是6个字符,把声明时的char name[3][5]改成char name[3][6]就行了:

    char name3[3][6] = {"name1","name2","name3"};
     printf("%s|%s|%s\n",name3[0],name3[1],name3[2]);

结果是:

name1|name2|name3

这时候,访问单个字符只需要按照下标访问就好了,比如name[1][2],访问的是"name2"里的下标为2的字符,就是'm'

问题来了,如果是按char* name[3],虽然可以访问每个元素,但是元素里的元素不方便访问,而char name[3][6]虽然每个分组和组内元素都比较好访问,但是每组元素必须长度相同,如果有一个"name22",就无法正常访问到了。这势必限制的数组在程序中的使用范围。而vector和map,queue等结构也是这样的道理,vector如果能满足所有场景,也就不会有其他结构了,增删改查论速度的话vector是很优秀的(目测这可能是研发出json的人的一个初衷吧)。当然,以上只是猜测~~hhh~~下面谈谈json::value, json::reader.

json::value

json是空间,value是类名,为了方便阅读,我只留下了少部分成员:

namespace json{
    class value{
        public:      
             class czstring {
             public:
                 enum duplicationpolicy 
                 {
                    noduplication = 0,
                    duplicate,
                    duplicateoncopy
                 };
                 czstring( int index );
                 czstring( const char *cstr, duplicationpolicy allocate );
                 ~czstring();
                 czstring &operator =( const czstring &other );
                 const char *c_str() const;
              private:
                 const char *cstr_;
                 int index_;
            };
            typedef std::map objectvalues;  
            value( int value );
            value( const char *value );
            value &operator[]( const char *key );
            value &operator[]( const std::string &key );  
           union valueholder
           {
               int int_;
               uint uint_;
               char *string_;
               objectvalues *map_;
           } value_;
    }//end class value
};

json::reader

namespace json{
    class reader{
    public:
        bool parse( const std::string &document,value &root,
                  bool collectcomments = true );
        bool parse( const char *begindoc, const char *enddoc, value &root,
                  bool collectcomments = true );
    };
};

好,这两个类先放在这里。现在假设一个情景:客户端用recv()接收服务器传回的学生信息,读取语文成绩。

recv的数据格式如下:

"{"student":[{"student":"f","when":1611893741,"code":-1,"msg":"18","class":"3-1"}],"detail":[{"port":8888,"timezone":8,"name":"zhang","math":70,"english":65,"chinese":"123","age":19,"reconfigtimes":0}],"id":1}"

熟悉吗,这是不是和数组一样,第一个元素是student,里面每个元素是一个键值对,用逗号分开,第二个元素是detail,里面也是键值对,比如第一个元素是"port":8888,以此类推。只是,这个"数组",在内存中是存储类型相同但长度不同的连续的存储空间,它最小的元素是一个可以转换任意基础或定义类型的联合 union valueholder。

json::value student = "接收的信息";
student["detail"];//表示[{"port":8888,"timezone":8,"name":"zhang","math":70,"english":65,"chinese":"123","age":19,"reconfigtimes":0}]

然而,想要取出学生的语文成绩123分,还需要再分析,这就需要了解一下map结构了;

typedef std::map objectvalues;

value类的每一个最基本的值如上所示,是类似于student["key"] = json::value();的结构。

好,现在开始分析啦:

第一步,用reader接收以上信息,代码如下:

char buf[1024];
int retval = recv(socket,buf,sizeof(buf),0);
if(retval <= 0){
    //error msg;
}
json::reader reader;
json::value student;
if(reader.parse(buf, student)) {
    //调用reader的成员函数parse(const std::string& ag1, value& ag2,bool ag3 = true);
    //把buf中的数据解析到student中,student就可以理解成一个二维数组的名称了
    //比如student["detail"],就相当于上面提到的第二个元素
}

第二步,确定语文成绩所在的具体位置

if(reader.parse(buf, student)) {
    //现在,detail相当于一个包含许多个map对象的一维数组
    json::value detail = student["detail"];
    //如果提前知道语文成绩所在下标,就可以直接这样
    //if(!detail[detail.size()-2]["chinese"].isnull()){
    //    cout << detail[detail.size()-2]["chinese"].asint();
    //}else{
    //    //err message;
    //}
    for(int i = 0; i < detail.size();i  ){
        //遍历detail,判断"chinese"是否存在
        //这样会把每个元素都循环一遍,数据量大时性能会下降
        if(!detail[i]["chinese"].isnull()){
            cout << detail[i]["chinese"].asint();
        }
    }
}