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