概述
cJSON
是 C
语言中的一个JSON
编解码器,非常轻量级,C开源代码汇总,代码量少,不到一千行,代码的可读性高,很适合作为 C
语言项目进行学习。
对于 json
格式编码与解码,其实就是类似于一个解释器,主要的原理是运用递归。
首先看下 cJSON.h
中定义的 cJSON
数据结构,
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
不管是数据类型、字符串类型还是对象类型都使用这个结构体,类型的信息通过type
来标记, cJSON
共定义了 7 中类型。
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3 //整型
#define cJSON_String 4 //字符串类型
#define cJSON_Array 5 //array 类型
#define cJSON_Object 6 //对象类型
如果是对象或者数组,采用的是双向链表来实现,链表中的每个节点表示数组中的一个元素或者对象中的一个字段。其中 child
表示头结点,next
、 prev
分别表示下一个节点和前一个节点。valuestring
、 valueint
、valuedouble
分别表示字符串、整数、浮点数的字面量。string
表示对象中的某一字段的名称,比如有这样的一个json
字符串,其中的 age
就用 string
来表示。
{'age' : 20}
cJSON
的 API 使用起来很简单,text 表示你需要解析的文件内容,注意释放内存,以免泄露。
char *out;cJSON *json;
json=cJSON_Parse(text);
if (!json) {printf("Error before: [%s]n",cJSON_GetErrorPtr());}
else
{
out=cJSON_Print(json);
cJSON_Delete(json);
printf("%sn",out);
free(out);
}
1、JSON的解析
进行解析分析前,我们先了解下 JSON
文件的格式。
Some JSON:
{
"name": "Jack ("Bee") Nimble",
"format": {
"type": "rect",
"width": 1920,
"height": 1080,
"interlace": false,
"frame rate": 24
}
}
JSON
的字符串的解析主要是通过 cJSON_Parse
函数来完成的。
cJSON *cJSON_Parse(const char *value)
{return cJSON_ParseWithOpts(value,0,0);}
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
const char *end=0;
cJSON *c=cJSON_New_Item();
ep=0;
if (!c) return 0; /* memory fail */
end=parse_value(c,skip(value));
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
if (return_parse_end) *return_parse_end=end;
return c;
}
- 第一步:先调用
cJSON_New_Item
函数 创建一个cJSON
节点,函数就是为 节点分配内存,并将对应的内存初始化为 0;
static cJSON *cJSON_New_Item(void)
{
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
if (node) memset(node,0,sizeof(cJSON));
return node;
}
- 调用
parse_value
函数解析文件,该函数是核心部分,在解析前,先skip(value)
,这里的意思就是将字符串前面的空格去掉;
static const char *skip(const char *in){
while (in && *in && (unsigned char)*in<=32)
in++;
return in;
}
- 最后一步中,函数的参数中提供的参数
require_null_terminated
是为了确认JSON
字符串必须以'