一.JSON格式简述
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。(来自“开源中国”资料)。
cJSON从名字可知,整个项目都是以极标准的C来写的,意思说,可以跨各种平台使用了。cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。
cJSON 开源项目位置:点击打开链接
更加详细的解释和示例请查看 http://www.json.org/ 主页。
cJSON,目前来说,就只有两个文件,一个cJSON.c 一个cJSON.h文件。使用的时候,自己创建好一个main.c文件后,将头文件include进去。
如果是在linux pc上,请使用以下命令进行编译:
gcc *.c cJSON.c -lm
记得编译时末尾链接libm库。
二.JSON结构体
熟悉使用cJSON库函数可从cJSON结构体入手,cJSON结构体如下所示:
几点说明
1.cJOSN结构体为一个双向列表,并可通过child指针访问下一层。
2.type变量决定数据项类型(键的类型),数据项可以是字符串可以是整形,也可以是浮点型。如果是整形值的话可从valueint,如果是浮点型的话可从valuedouble取出,以此类推。
3.string可理解为节点的名称,综合此处的第2点可理解为“键”的名称。
4.如果是对象或者数组,采用的是双向链表来实现,链表中的每一个节点表示数组中的一个元素或者对象中的一个字段。其中child表示头结点,next、prev分别表示下一个节点和前一个节点。valuestring、valueint、valuedouble分别表示字符串、整数、浮点数的字面量。
cJSON作为Json格式的解析库,其主要功能无非就是构建和解析Json格式了,用途就是一端将要发送的数据已cjson形式封装,然后发送,另一端收到此数据后,还是按cjson形式解析,就得到想要的数据了。
三.JSON各个API的使用
①:
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
这些宏定义是对结构体type的值定义,处理时只需要将type的值&255进行位运算,即可得到json里储存的数据类型。
②:
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; //同一级元素使用链表存储
struct cJSON *child; //如果是一个object或array的话,child为第一个儿子的指针
int type; //value的类型
char *valuestring; //如果这个value是字符串类型,则此处为字符串值
int valueint; //如果是数字的话,整数值
double valuedouble; //如果是数字的话,浮点数值
char *string; //json对象的名称
} cJSON;
③:
cJSON内存管理:
hook管理函数:
在 c 语言中内存一般是 malloc 和 free 的。
为了方便用户自由的管理内存, cjson 使用 Hook 技术来让使用者可以自定义内存管理函数。
即用户自定义 malloc 和 free.
具体实现方式可以参考下面的代码, 默认使用系统的 malloc 和 free 函数, 用过 cJSON_InitHooks 函数可以替换成用户自定义的 malloc 和 free 函数。
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* 对cJSON提供的分配,重分配,释放内存初始化函数 */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
④:各种API调用
/* 将普通的json字符串处理成json对象,注意:使用完后需要将json指针释放*/
extern cJSON *cJSON_Parse(const char *value);
/*将cjson格式的数据,转换为普通字符串的新式,虽然json格式的数据也是一个字符串的样子,但这时候还是无法当成普通的字符串使用,注意:使用完后需要将json指针释放*/
extern char *cJSON_Print(cJSON *item);
/*将cjson格式的数据,以没有格式的形式转换成普通的字符串:也就是字符串中间不会有"\n" "\t"之类的东西存在,注意:使用完后需要将json指针释放*/
extern char *cJSON_PrintUnformatted(cJSON *item);
/*使用缓冲策略将cJSON实体呈现为文本。预缓冲是对最终大小的猜测。猜测良好可以减少重新分配。fmt=0给出未格式化,=1给出格式化*/
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/*释放内存*/
extern void cJSON_Delete(cJSON *c);
/*获取数组里面元素的个数,指针array是一个指向数组的对象*/
extern int cJSON_GetArraySize(cJSON *array);
/*获取数组里面的元素,这个元素也可能是对象,item是对应元素的下标*/
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/*获取键值内容(对象里面的对象),用一个新的 json 指针,指向该对象*/
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/*判断是否有key键值是string的项,如果有返回1,否则返回0*/
extern int cJSON_HasObjectItem(cJSON *object,const char *string);
/*当使用cJSON_Prase()函数解析数据时,如果失败就可以调用该函数,该函数会返回错误的原因*/
extern const char *cJSON_GetErrorPtr(void);
/* 这些是构造json的一些API */
extern cJSON *cJSON_CreateNull(void); //创建一个空对象,暂时保留以后可能要用到
extern cJSON *cJSON_CreateTrue(void); //创建一个true的对象
extern cJSON *cJSON_CreateFalse(void); //创建一个false的对象
extern cJSON *cJSON_CreateBool(int b); //创建一个bool对象
extern cJSON *cJSON_CreateNumber(double num); //创建一个数字类型的对象
extern cJSON *cJSON_CreateString(const char *string); //创建一个字符串类型的对象
extern cJSON *cJSON_CreateArray(void); //创建一个数组类型的对象
extern cJSON *cJSON_CreateObject(void); //创建一个根对象,它是cjson格式的头结点
/* 创建数组其中里面可以设定为不同的数据类型*/
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); //整形
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); //浮点型
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); //double型
extern cJSON *cJSON_CreateStringArray(const char **strings,int count); //字符串类型
/* 向数组中添加对象*/
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
/*向对象中添加键值对,值的类型与相关函数有关*/
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
/*当字符串肯定是const(即一个文字,或者与常量一样好),并且肯定能在cJSON对象中存活下来时,可以使用这个*/
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);
/* 将对项的引用附加到指定的数组/对象。当您想要将现有的cJSON添加到新的cJSON中,但又不想破坏现有的cJSON时,请使用此选项 */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* 从数组/对象中删除/分离项 */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* 更新数组项 */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);//右移
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* 复制一个cJSON项 */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate将在新的内存中创建与传递的cJSON相同的新项需要释放。递归!=0,它将复制与项连接的任何子节点。item->next和->prev指针从Duplicate返回时总是为0。*/
/* ParseWithOpts允许您要求(并检查)JSON终止为空,并检索到解析的最后一个字节的指针 */
/* 如果在return_parse_end中提供ptr,并且解析失败,那么return_parse_end将包含一个指向错误的指针。如果没有,那么cJSON_GetErrorPtr()就可以了。 */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
extern void cJSON_Minify(char *json);
/* 用于快速创建内容的宏. */
#define cJSON_AddNullToObject(object,name)
#define cJSON_AddTrueToObject(object,name)
#define cJSON_AddFalseToObject(object,name)
#define cJSON_AddBoolToObject(object,name,b)
#define cJSON_AddNumberToObject(object,name,n)
#define cJSON_AddStringToObject(object,name,s)
/*当分配一个整数值时,它也需要传播到valuedouble */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
/*用于迭代数组的宏 */
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
先分支再综合,先写子类在写父类