json-c-0.9库解析

json-c-0.9库解析



项目中使用json格式字符串进行进程间通信,使用json-c-0.9库进行字符串解析和设置,现将json-c-0.9库进行说明,欢迎指正~~


1. 编译

  1. ./configure CC= –host= –prefix=PATH
    指定编译器、主机类型、安装路径(绝对路径),默认路径/usr/local
  2. make && make install
    修改config.h.in屏蔽#undef malloc 和 #undef realloc后执行,
    这样json就已经安装成功。
  3. -std=c99 -I/PATH/incldue/json -L/PATH/lib -ljson
    在程序中使用json的api只需要在编译程序时添加以上信息
    例如这样编译库中test1.c:
    gcc test1.c -o test1 -std=c99 -I/PATH/incldue/json -L/PATH/lib -ljson

2. 数据结构(data structures)

比较重要的数据结构:

1. struct json_object
struct json_object
{
  enum json_type o_type;            //json对象类型
  json_object_delete_fn *_delete;   //free json对象
  json_object_to_json_string_fn *_to_json_string;   //转换json对象为json格式的字符串
  int _ref_count;                   //json对象引用计数,初始化为1
  struct printbuf *_pb;             //存储json对象转换后的字符串内存区域地址
  union data {
    boolean c_boolean;              //boolean类型json对象的数值
    double c_double;                //double类型json对象的数值
    int c_int;                      //int类型json对象的数值
    struct lh_table *c_object;      //存储object类型json对象的hash_table地址
    struct array_list *c_array;     //存储array类型json对象的字符串数组地址
    char *c_string;                 //存储string类型json对象的地址
  } o;
};
2.  struct json_tokener
struct json_tokener
{
  char *str;
  struct printbuf *pb;      //用于分类存储待解析字符串的buffer

  int depth;                //结构体成员stack的depth
  int is_double;            //value是double or int
  int st_pos;               //string中某字符的position,string包括:null,true,false,unicode
  int char_offset;          //某字符在待解析字符串中的offset

  ptrdiff_t err;            //字符串解析出错代码
  unsigned int ucs_char;    //unicode的值
  char quote_char;          //存储引号"
  struct json_tokener_srec stack[JSON_TOKENER_MAX_DEPTH]; //存储待解析字符串中所有的json对象
};
3. struct json_object 和 struct json_tokener 的成员struct printbuf定义如下,定义一个buffer,用于存储字符串;
struct printbuf {
  char *buf;
  int bpos;     //buf中已经使用的数量
  int size;     //buf的size
};
4. struct json_tokener 的成员struct json_tokener_srec定义如下,定义一个stack,用于存储不同类型object对象;
struct json_tokener_srec
{
  enum json_tokener_state state, saved_state;
  struct json_object *obj;  //暂未使用
  struct json_object *current;
  char *obj_field_name;     //object某一个field的name
};

3. 文件(files)

获取json-c-0.9.tar.gz解压后,包含的源码文件如图,下面内容大致介绍文件的主要代码:

json-c-0.9源码文件列表

  • json_object.c
    定义json对象的操作函数,包括新建、删除、转换、添加等函数;

    1. json_object_new()/json_object_to_json_string()/json_object_generic_delete()
    
      三个函数分别new一个json对象/转换json对象为json格式的字符串/删除json对象,相当于父类。
    

json_object_new()实现:

    static struct json_object* json_object_new(enum json_type o_type)
    {
        struct json_object *jso;

        jso = (struct json_object*)calloc(sizeof(struct json_object), 1);       //new一个json_object对象,并赋值
        if(!jso) return NULL;
        jso->o_type = o_type;
        jso->_ref_count = 1;
        jso->_delete = &json_object_generic_delete;
        ...
        return jso;
    }

json_object_to_json_string()实现

    const char* json_object_to_json_string(struct json_object *jso)
    {
        if(!jso) return "null";
        if(!jso->_pb) {
        if(!(jso->_pb = printbuf_new())) return NULL;
        } else {
            printbuf_reset(jso->_pb);//如果存在,则复位存储json对象转换后的字符串的内存区域,否则new一个新区域
        }
            if(jso->_to_json_string(jso, jso->_pb) < 0) return NULL;    //依据传入的json对象(struct json_object *jso),
                                    //jso->_to_json_string(jso, jso->_pb)调用相应的json_object_**_to_json_string()函数
            return jso->_pb->buf;
    }

json_object_generic_delete()实现

    static void json_object_generic_delete(struct json_object* jso)
    {
        ...
        printbuf_free(jso->_pb);
        free(jso);
    }
    2.  json_object_new_**()/json_object_**_to_json_string()/json_object_**_delete()

       三个系列函数分别new一个“子类”的json对象/转换“子类”的json对象为json格式的字符串/删除“子类”的json对象;
       其中的“子类”的json对象包括boolean、double、int、object、array、string等类型;

以object类型json对象为例:

json_object_new_**()实现

    struct json_object* json_object_new_object(void)
    {
        struct json_object *jso = json_object_new(json_type_object);
        if(!jso) return NULL;
        jso->_delete = &json_object_object_delete;                  //在json_object_new()基础上填充._to_json_string、.o.c_object方法,
        jso->_to_json_string = &json_object_object_to_json_string;  //并覆写._delete方法
        jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES,
                        NULL, &json_object_lh_entry_free);
        return jso;
    }

json_object_**_to_json_string()实现

    static int json_object_object_to_json_string(struct json_object* jso,
                     struct printbuf *pb)
    {
        int i=0;
        struct json_object_iter iter;
        sprintbuf(pb, "{"); //object类型json对象的json格式字符串开始

        /* CAW: scope operator to make ANSI correctness */
        /* CAW: switched to json_object_object_foreachC which uses an iterator struct */
        json_object_object_foreachC(jso, iter) {                //遍历json对象所有的key和value
            if(i) sprintbuf(pb, ",");
            sprintbuf(pb, " \"");
            json_escape_str(pb, iter.key);
            sprintbuf(pb, "\": ");
            if(iter.val == NULL) sprintbuf(pb, "null");
            else iter.val->_to_json_string(iter.val, pb);   //依据json对象(iter.val),选择相应的json_object_**_to_json_string()
            i++;
        }

        return sprintbuf(pb, " }"); //object类型json对象的json格式字符串结束
    }

json_object_**_delete()实现

    static void json_object_object_delete(struct json_object* jso)
    {
            lh_table_free(jso->o.c_object); //free hash_table
        json_object_generic_delete(jso);    //free json对象
    }
    3. json_object_get()/json_object_put()

      增加json对象引用计数/减少json对象引用计数
    4. json_object_object_add()/json_object_object_get()/json_object_object_del()

        添加一个feild到object类型的json对象/从object类型的json对象获取一个feild/删除object类型的json对象中一个feild
    5. json_object_array_add()/json_object_array_put_idx()/json_object_array_get_idx()

        添加一个element(json对象)到array类型的json对象尾部/添加一个element到array类型的json对象的
        某个位置/获取array类型的json对象的某个位置的element

  • json_tokener.c
    定义解析字符串为json对象函数以及两个重要的宏POP_CHAR(dest, tok)和ADVANCE_CHAR(str, tok)

POP_CHAR(dest, tok)

#define POP_CHAR(dest, tok)                                                  \
(((tok)->char_offset == len) ?                                          \
     (((tok)->depth == 0 && state == json_tokener_state_eatws && saved_state == json_tokener_state_finish) ? \
        (((tok)->err = json_tokener_success), 0)                              \
        :                                                                   \
        (((tok)->err = json_tokener_continue), 0)                             \
    ) :                                                                 \
     (((dest) = *str), 1)                                                 \
 )      //将字符*str赋值给dest,并返回1;当到达字符串结尾(tok->char_offset == len)时检查depth、state和saved_state,设置tok->err,并返回0

ADVANCE_CHAR(str, tok)

#define ADVANCE_CHAR(str, tok) \
    ( ++(str), ((tok)->char_offset)++, c)   //遍历字符串str,同步递增tok->char_offset,并返回字符c
        //和POP_CHAR(c, tok)一起使用,实现对字符串str的字符进行遍历,并设置遍历的结果状态(tok->err)
定义的函数包括新建/删除json_tokener对象函数json_tokener_new()/json_tokener_free(),以及解析函数json_tokener_parse**();
其中json_tokener_parse_ex()函数很重要,此函数通过state和saved_state两个状态控制函数流程,state和saved_state 取下面枚举值;
enum json_tokener_state {
    json_tokener_state_eatws,                   //ew
    json_tokener_state_start,                   //st
    json_tokener_state_finish,                  //fi
    ...
    json_tokener_state_string,                 //str
    json_tokener_state_string_escape,          //str_esc
    json_tokener_state_escape_unicode,         //uni
    ...
    json_tokener_state_array,                  //arr
    json_tokener_state_array_add,              //arr_a
    json_tokener_state_array_sep,              //arr_s
    json_tokener_state_object_field_start,     //ofs
    json_tokener_state_object_field,           //of
    json_tokener_state_object_field_end,       //ofe
    json_tokener_state_object_value,           //ov
    json_tokener_state_object_value_add,       //ova
    json_tokener_state_object_sep              //os
};
json_tokener_parse_ex() 函数可以解析boolean、double、int、object、array、string等类型的json对象,以object类型的json对象的
解析过程为例,说明解析流程(重点介绍解析过程中state和saved_state 转换过程,详细流程查看源码)

object类型json对象解析状态变换流程

  • linkhash.c
    这个文件中函数用于处理存储object类型json对象的hash_table,包括新建hash_table函数lh_table_new()/lh_**_table_new(),删除hash_table
    函数lh_table_free(),添加record到hash_table函数lh_table_insert(),删除record函数lh_table_delete()/lh_table_delete_entry(),查找record
    函数lh_table_lookup()/lh_table_lookup_entry();
    关于hash_table的知识请参考预备知识 : linux内核哈希表hlist

  • arraylist.c
    这个文件中函数用于处理存储array类型json对象的arraylist,包括新建arraylist函数array_list_new(),删除arraylist函数array_list_free(),
    添加元素到arraylist函数array_list_add()/array_list_put_idx(),查找元素函数array_list_get_idx();

  • debug.c
    定义不等等级的日志输出函数以及对应的宏,MC_DEBUG()/mc_debug()/..;

  • printbuf.c
    定义内存操作函数,新建函数printbuf_new(),内存拷贝函数printbuf_memappend()等;

  • json_util.c
    定义从文件读取字符串解析为json对象函数json_object_from_file()和将json对象转化为json格式字符串写入文件函数json_object_to_file();


4. json格式通信的收发流程

  • 接收:
    read()(读取字符串数据)
    –> json_tokener_parse()(从字符串数据中解析json对象)
    –> json_object_get_*()(从json对象中获取数据value,如int、double、string、array、object等)
  • 发送:
    json_object_new_*()(生成json对象)
    –> json_object_object_add()/json_object_array_add()/json_object_to_json_string().. (往json对象添加数据并转换字符串数据)
    –> write()(发送字符串数据)

5. 举例

项目中使用json格式字符串进行进程间通信,流程如下:
读取进程间通信数据(字符串) –> 解析出json对象 –> 处理json对象 –> … –> 生成json对象并添加数据 –> 转换json对象为json格式字符串并发送


6. 小结

本文简绍项目中使用的json-c-0.9库解析、处理json格式字符串的实现流程,并简单说明使用json-c-0.9进行通信的原理,欢迎指正和讨论^_^。


疑问

  1. json_object.h 30~38行的定义有什么用?
    printbuf、lh_table、… 这些结构体在别的地方已经定义,再次定义的作用是什么..
    /* forward structure definitions */

    typedef int boolean;
    typedef struct printbuf printbuf;
    typedef struct lh_table lh_table;
    typedef struct array_list array_list;
    typedef struct json_object json_object;
    typedef struct json_object_iter json_object_iter;
    typedef struct json_tokener json_tokener;

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解析JSON文件,可以使用json-c,具体步骤如下: 1. 引入json-c的头文件 ```c #include <json-c/json.h> ``` 2. 读取JSON文件内容 ```c FILE *fp = fopen("filename.json", "r"); if (fp == NULL) { printf("Failed to open file\n"); return -1; } char buffer[1024]; fread(buffer, 1, 1024, fp); fclose(fp); ``` 3. 解析JSON文件内容 ```c struct json_object *json_obj = json_tokener_parse(buffer); ``` 4. 获取JSON对象的值 ```c // 获取字符串类型的值 const char *str_value; json_object_object_get_ex(json_obj, "key", &str_value); printf("%s\n", str_value); // 获取整数类型的值 int int_value; json_object_object_get_ex(json_obj, "key", &int_value); printf("%d\n", int_value); // 获取数组类型的值 struct json_object *arr_obj; json_object_object_get_ex(json_obj, "key", &arr_obj); int arr_len = json_object_array_length(arr_obj); for (int i = 0; i < arr_len; i++) { struct json_object *item = json_object_array_get_idx(arr_obj, i); // 处理数组项 } ``` 完整的示例代码如下: ```c #include <stdio.h> #include <json-c/json.h> int main() { FILE *fp = fopen("example.json", "r"); if (fp == NULL) { printf("Failed to open file\n"); return -1; } char buffer[1024]; fread(buffer, 1, 1024, fp); fclose(fp); struct json_object *json_obj = json_tokener_parse(buffer); const char *str_value; json_object_object_get_ex(json_obj, "name", &str_value); printf("name: %s\n", str_value); int age_value; json_object_object_get_ex(json_obj, "age", &age_value); printf("age: %d\n", age_value); struct json_object *hobby_arr_obj; json_object_object_get_ex(json_obj, "hobbies", &hobby_arr_obj); int hobby_arr_len = json_object_array_length(hobby_arr_obj); printf("hobbies:\n"); for (int i = 0; i < hobby_arr_len; i++) { struct json_object *item = json_object_array_get_idx(hobby_arr_obj, i); printf("- %s\n", json_object_get_string(item)); } json_object_put(json_obj); return 0; } ``` 需要注意的是,使用完json对象后,需要调用`json_object_put`函数释放内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值