json-c的树型封装(json-tree)

后学
2023-12-01

arvik以前运用json-c库的时候对json-c库做了一下封装,以简化json取值/设置过程。

由于json-c在取值的时候必须层层获取对象,当一个json对象中嵌套许多json对象的时候,取值就变得越来越繁琐。json-tree的封装就是为了消除运用json-c取值的中间过程。——json-tree的写作背景

以下就简要介绍下吧

使用描述

取值

对于如下一个json对象root来说,想获取ssid1的值只需调用json-tree中的封装JsonGetStr(root, “data.wifi0.ss1.ssid1”)即可,其他取值类似

{
    "header": {
        "dappid": 101,
        "cmd": 1
    },
    "data": {
        "wifi0": {
            "ss1": {
                "ssid1": "openwrt_ssid1",
                "iso": "none"
            },
            "ss2": {
                "ssid2": "openwrt_ssid2",
                "iso": "none"
            }
        },
        "wifi1":{}
    }
}

设值

对于一个空的json对象root来说,设置如上ssid1的值,只需调用JsonSetStr(root, “data.wifi0.ss1”, “ssid1”, “openwrt_ssid1”)即可。

说明:json-tree没有对数组的封装,故对数组的取值/设值不能一步到位,需要先一步获取数组对象,再设值/取值。


源码

json-tree.c源码

/*
file:   json-tree.c
porpose:    packaged the json-c API
author: arvik
email:  1216601195@qq.com
blog:   http://blog.csdn.net/u012819339
*/

#include <stdio.h>
#include <stdlib.h>

#ifndef __USE_BSD
#define __USE_BSD
#endif

#include <string.h>

#include "json-tree.h"

/*
description: 获取json对象,注意:1. 该函数线程不安全,因为使用了strtok函数(之后会换成线程安全的strsep函数)。
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
    value:查找到的json对象指针存放地址
返回:bool类型
使用方法:
一个json对象内容如下(指针root对应这个对象):{"header":{"cmd":{"cmd1":"arg1", "cmd2":"arg2"}, "ctr":"msg"}, "data":["data1", "data2"]}
如果要获取键值对{"cmd2":"arg2"}则使用JsonGetObj(root, "header.cmd.cmd2", &obj)
*/
PUBLIC_API json_bool JsonGetObj(struct json_object *root, const char *keypath, struct json_object **value)
{
    struct json_object *sub_obj = root;
    char *sub_key;
    char path[240];
    char *str_path = path;

    if (keypath == NULL || root == NULL || is_error(root))
    {
        *value = NULL;
        return FALSE;
    }

    memset(path, 0, sizeof(path));
    strcpy(path, keypath);
//  printf("str:%s\n", str_path);
/*
    sub_key = strtok(str_path, ".");
    if (!json_object_object_get_ex(root, sub_key, &sub_obj))
    {
        *value = NULL;
        return FALSE;
    }
    while((sub_key = strtok(NULL, ".")) != NULL)  */
    while((sub_key = strsep(&str_path, ".")) != NULL)
    {   

        if (json_object_object_get_ex(sub_obj, sub_key, &sub_obj) == FALSE)
        {
            *value = NULL; 
            return FALSE;
        }
    }

    *value = sub_obj;
    return TRUE;
}

/*
description: 获取键值对的字符串值
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
返回:字符串首地址
使用方法:一个json对象obj如下,{ \"header\":{\"cmd\":\"0\", \"sapp\":\"022\", \"dapp\":\"0x12\"}, \"data\":{\"wifi\": {\"ssid\":\"arvik\"}} }
使用JsonGetStr(obj, "data.wifi.ssid")即可获取ssid的字符串值
*/
PUBLIC_API char *JsonGetStr(struct json_object *root, const char *keypath)
{
    struct json_object *goal_obj;

    if(JsonGetObj(root, keypath, &goal_obj))
        return (char *)json_object_get_string(goal_obj);

    return NULL;
}

PUBLIC_API int64_t JsonGetInt64(struct json_object *root, const char *keypath)
{
    struct json_object *goal_obj;

    if(JsonGetObj(root, keypath, &goal_obj))
        return json_object_get_int(goal_obj);

    return -1;
}

PUBLIC_API json_bool JsonGetBool(struct json_object *root, const char *keypath)
{
    struct json_object *goal_obj;

    if(JsonGetObj(root, keypath, &goal_obj))
        return json_object_get_boolean(goal_obj);

    return FALSE;
}

/*
description: 创建json路径
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
返回:字符串首地址
使用方法:一个json对象obj如下,{ \"header\":{\"cmd\":\"0\", \"sapp\":\"022\", \"dapp\":\"0x12\"}, \"data\":{\"wifi\": {\"ssid\":\"arvik\"}} }
使用JsonGetStr(obj, "data.wifi.ssid")即可获取ssid的字符串值
*/
struct json_object *JsonCreatePath(struct json_object *root, const char *c_path)
{
    struct json_object *sub_obj = root, *tmp_obj = root, *new_obj;
    char path[240];
    char *p_str = path, *r_str;

    if (root == NULL || is_error(root))
        return NULL;

    if(c_path == NULL)
        return root;    

    memset(path, 0, sizeof(path));
    strcpy(path, c_path);

    while((r_str = strsep(&p_str, ".")) != NULL )
    {
        //printf("if has path:%s\n", r_str);
        if(r_str)
        {
            tmp_obj = sub_obj;
            if(json_object_object_get_ex(sub_obj, r_str, &sub_obj) == FALSE) //查询该层路径是否存在
                goto addobj;  //此时开始构造以后的路径
            else
                continue;  //存在,继续查询
        }
    }
    return sub_obj; //路径已到尽头,每层都存在

addobj:
    sub_obj = tmp_obj;
    do
    {
        //printf("create:%s\n", r_str);
        if(r_str)
        {
            if((new_obj = JsonObjNew()) != NULL)
            {
                json_object_object_add(sub_obj, r_str, new_obj);
                sub_obj = new_obj;
            }
            else
                return NULL;
        }
    }while((r_str = strsep(&p_str, ".")) != NULL);

    return sub_obj; //创建完毕
}


/*
description: 创建json路径,并在此路径下设置json对象
参数:
    root:json对象
    path: 相对于root的路径,每层路径用“.”隔开
    key:键值
    val: json对象值(字符串)
返回:bool
使用方法:一个json对象obj如下,{ \"header\":{\"cmd\":\"0\", \"sapp\":\"022\", \"dapp\":\"0x12\"}, \"data\":{\"wifi\": {\"ssid\":\"arvik\"}} }
使用JsonSetStr(obj, "data.wifi", "ssid", "arvik")即可设置ssid值,如果中间路径不存在则尝试创建出路径
*/
PUBLIC_API json_bool JsonSetStr(struct json_object *root, const char *path, const char *key, const char *val)
{
    struct json_object *goal_obj;
    struct json_object *new_obj = NULL;

    if (key == NULL || root == NULL || is_error(root))
        return FALSE;

    if (val == NULL)
        new_obj = json_object_new_string("");
    else
        new_obj = json_object_new_string(val);

    if (new_obj == NULL || is_error(new_obj) || json_object_get_type(new_obj) != json_type_string) 
    {
        return FALSE;
    }

    if((goal_obj = JsonCreatePath(root, path)) != NULL)
    {
        json_object_object_add(goal_obj, key, new_obj);
        return TRUE;
    }

    JsonObjPut(new_obj);
    return FALSE;
}

/*
description: 创建json路径,并在此路径下设置json对象
参数:
    root:json对象
    path: 相对于root的路径,每层路径用“.”隔开
    key:键值
    val: json对象值(字符串)
返回:bool
使用方法:同上
*/
PUBLIC_API json_bool JsonSetInt64(struct json_object *root, const char *path, const char *key, int64_t val)
{
    struct json_object *goal_obj;
    struct json_object *new_obj = NULL;

    if (key == NULL || root == NULL || is_error(root))
        return FALSE;

    new_obj = json_object_new_int(val);
    if (new_obj == NULL || is_error(new_obj) || json_object_get_type(new_obj) != json_type_int) 
    {
        return FALSE;
    }

    if((goal_obj = JsonCreatePath(root, path)) != NULL)
    {
        json_object_object_add(goal_obj, key, new_obj);
        return TRUE;
    }

    JsonObjPut(new_obj);
    return FALSE;   
}

/*
description: 创建json路径,并在此路径下设置json对象
参数:
    root:json对象
    path: 相对于root的路径,每层路径用“.”隔开
    key:键值
    val: json对象值(字符串)
返回:bool
使用方法:同上
*/
PUBLIC_API json_bool JsonSetBool(struct json_object *root, const char *path, const char *key, json_bool val)
{
    struct json_object *goal_obj;
    struct json_object *new_obj = NULL;

    if (key == NULL || root == NULL || is_error(root))
        return FALSE;

    new_obj = json_object_new_boolean(val);
    if (new_obj == NULL || is_error(new_obj) || json_object_get_type(new_obj) != json_type_boolean) 
    {
        return FALSE;
    }

    if((goal_obj = JsonCreatePath(root, path)) != NULL)
    {
        json_object_object_add(goal_obj, key, new_obj);
        return TRUE;
    }

    JsonObjPut(new_obj);
    return FALSE;
}

/*
description: 创建json路径,并在此路径下设置json对象
参数:
    root:json对象
    path: 相对于root的路径,每层路径用“.”隔开
    key:键值
    val: json对象值(字符串)
返回:bool
使用方法:同上
*/
PUBLIC_API json_bool JsonSetObj(struct json_object *root, const char *path, const char *key, struct json_object *val)
{
    struct json_object *goal_obj;

    if (root == NULL || val==NULL || is_error(root) || is_error(val) || key == NULL)
        return FALSE;

    if((goal_obj = JsonCreatePath(root, path)) != NULL)
    {
        json_object_object_add(goal_obj, key, val);
        return TRUE;
    }

    return FALSE;       
}

json-tree.h源码:

/*
file:   json-tree.h
porpose:    消除json-c取值与设置值的中间步骤,力图一步到位!
author: arvik
email:  1216601195@qq.com
blog:   http://blog.csdn.net/u012819339
*/

#pragma once

#ifndef __JSON_TREE_H
#define __JSON_TREE_H

#include <stdint.h>
#include "json-c/json.h"
//#include "json/json.h"

#ifndef PUBLIC_API
#define PUBLIC_API
#endif

/*
#ifndef json_bool
#define json_bool int
#endif
*/
//#define json_object_object_get_ex(a, b, c) (*c = json_object_object_get(a, b))

#define JsonStrToken(json_str)  json_tokener_parse(json_str)    
#define JsonObjPut(obj) json_object_put(obj)
#define JsonObjNew()    json_object_new_object()
#define JsonObjToStr(obj)   json_object_to_json_string(obj)

#define JsonArrayNew()  json_object_new_array()
#define JsonArrayAdd(jso, val)  json_object_array_add(jso, val)
#define JsonArrayLen(jso)   json_object_array_length(jso)

#define JsonIntNew(i)   json_object_new_int(i)
#define JsonStrNew(str)     json_object_new_string(str)
#define JsonBoolNew(b)      json_object_new_boolean(b)

/*
description: 获取json对象
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
    value:查找到的json对象指针存放地址
返回:bool类型
使用方法:
一个json对象内容如下(指针root对应这个对象):{"header":{"cmd":{"cmd1":"arg1", "cmd2":"arg2"}, "ctr":"msg"}, "data":["data1", "data2"]}
如果要获取键值对{"cmd2":"arg2"}则使用JsonGetObj(root, "header.cmd.cmd2", &obj)
*/
PUBLIC_API json_bool JsonGetObj(struct json_object *root, const char *keypath, struct json_object **value);

/*
description: 获取键值对的字符串值
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
返回:字符串首地址
使用方法:一个json对象obj如下,{ \"header\":{\"cmd\":\"0\", \"sapp\":\"022\", \"dapp\":\"0x12\"}, \"data\":{\"wifi\": {\"ssid\":\"arvik\"}} }
使用JsonGetStr(obj, "data.wifi.ssid")即可获取ssid的字符串值
*/
PUBLIC_API char *JsonGetStr(struct json_object *root, const char *keypath);

/*
description: 获取键值对的int64_t值
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
返回:字符串首地址
使用方法:同上类似
*/
PUBLIC_API int64_t JsonGetInt64(struct json_object *root, const char *keypath);

/*
description: 获取键值对的bool值
参数:
    root:json对象
    keypath: 相对于root的路径,每层路径用“.”隔开
返回:字符串首地址
使用方法:同上类似
*/
PUBLIC_API json_bool JsonGetBool(struct json_object *root, const char *keypath);



PUBLIC_API json_bool JsonSetStr(struct json_object *root, const char *path, const char *key, const char *val);

PUBLIC_API json_bool JsonSetInt64(struct json_object *root, const char *path, const char *key, int64_t val);

PUBLIC_API json_bool JsonSetBool(struct json_object *root, const char *path, const char *key, json_bool val);

PUBLIC_API json_bool JsonSetObj(struct json_object *root, const char *path, const char *key, struct json_object *val);

#endif
 类似资料: