我们在项目中经常要用到json格式数据进行通讯,特别是还要做ARM开发板上实现,处理JSON,自己手撕数据处理是件麻烦的事情,不过现在我们有第三方库了!那就是cJson!
cJson官方库:
https://github.com/DaveGamble/cJSONhttps://github.com/DaveGamble/cJSON或者:
git clone https://github.com/DaveGamble/cJSON
只需要保留cJSON.c和cJSON.h两个核心文件。
首先呢,cJSON提供了一种变量类型叫cJSON,我们通过看cJSON.h文件可知其是个结构体:
/* The cJSON structure: */ typedef struct cJSON { /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ struct cJSON *next; struct cJSON *prev; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ struct cJSON *child; /* The type of the item, as above. */ int type; /* The item's string, if type==cJSON_String and type == cJSON_Raw */ char *valuestring; /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ int valueint; /* The item's number, if type==cJSON_Number */ double valuedouble; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ char *string; } cJSON;
从这个结构体可以看出,这个json结构体内容支持JSON对象,整数,字符串,双精度浮点数。
要从一个json数据的节点中获取节点下数据,可以通过如下函数:
/* Returns the number of items in an array (or object). */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); /* Get item "string" from object. Case insensitive. */ CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* Check item type and return its value */ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
其中,比较常用的有
/* 获取节点下的json数据 */ CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); /* 获取节点下的字符数据 */ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); /* 获取节点下的数字数据 */ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
cJson提供了不少创建或者添加对象的方法:
/* These calls create a cJSON item of the appropriate type. */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); /* raw json */ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* Create a string where valuestring references a string so * it will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); /* Create an object/array that only references it's elements so * they will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); /* These utilities create an Array of count items. * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); /* Append item to the specified array/object. */ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before * writing to `item->string` */ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
不止有添加或者说创建,还有删除。
/* Remove/Detach items from Arrays/Objects. */ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
不过删除功能一般不常用,甚至还有替换对象,这个功能同学们就自行看库源代码进行使用吧,此处不做过多讲解。
使用这个库很简单,只需要将那两个核心文件添加到项目路径。
#include"cJSON.h"
即可开始使用这个库里的任何函数啦。
来个经典案例,要解析的json数据如下:
{ "semantic": { "slots": { "name": "张三" } }, "rc": 0, "operation": "CALL", "service": "telephone", "text": "打电话给张三" }
解析代码如下:
#include <stdio.h> #include <stdlib.h> #include "cJSON.h" void printJson(cJSON * root)//以递归的方式打印json的最内层键值对 { for(int i=0; i<cJSON_GetArraySize(root); i++) //遍历最外层json键值对 { cJSON * item = cJSON_GetArrayItem(root, i); if(cJSON_Object == item->type) //如果对应键的值仍为cJSON_Object就递归调用printJson printJson(item); else //值不为json对象就直接打印出键和值 { printf("%s->", item->string); printf("%s\n", cJSON_Print(item)); } } } int main() { char * jsonStr = "{\"semantic\":{\"slots\":{\"name\":\"张三\"}}, \"rc\":0, \"operation\":\"CALL\", \"service\":\"telephone\", \"text\":\"打电话给张三\"}"; cJSON * root = NULL; cJSON * item = NULL;//cjson对象 root = cJSON_Parse(jsonStr); if (!root) { printf("Error before: [%s]\n",cJSON_GetErrorPtr()); } else { printf("%s\n", "有格式的方式打印Json:"); printf("%s\n\n", cJSON_Print(root)); printf("%s\n", "无格式方式打印json:"); printf("%s\n\n", cJSON_PrintUnformatted(root)); printf("%s\n", "一步一步的获取name 键值对:"); printf("%s\n", "获取semantic下的cjson对象:"); item = cJSON_GetObjectItem(root, "semantic");// printf("%s\n", cJSON_Print(item)); printf("%s\n", "获取slots下的cjson对象"); item = cJSON_GetObjectItem(item, "slots"); printf("%s\n", cJSON_Print(item)); printf("%s\n", "获取name下的cjson对象"); item = cJSON_GetObjectItem(item, "name"); printf("%s\n", cJSON_Print(item)); printf("%s:", item->string); //看一下cjson对象的结构体中这两个成员的意思 printf("%s\n", item->valuestring); printf("\n%s\n", "打印json所有最内层键值对:"); printJson(root); } return 0; }
来个经典案例,要生成的json数据如下:
{ "semantic": { "slots": { "name": "张三" } }, "rc": 0, "operation": "CALL", "service": "telephone", "text": "打电话给张三" }
生成代码如下:
#include <stdio.h> #include "cJSON.h" int main() { cJSON * root = cJSON_CreateObject(); cJSON * item = cJSON_CreateObject(); cJSON * next = cJSON_CreateObject(); cJSON_AddItemToObject(root, "rc", cJSON_CreateNumber(0));//根节点下添加 cJSON_AddItemToObject(root, "operation", cJSON_CreateString("CALL")); cJSON_AddItemToObject(root, "service", cJSON_CreateString("telephone")); cJSON_AddItemToObject(root, "text", cJSON_CreateString("打电话给张三")); cJSON_AddItemToObject(root, "semantic", item);//root节点下添加semantic节点 cJSON_AddItemToObject(item, "slots", next);//semantic节点下添加item节点 cJSON_AddItemToObject(next, "name", cJSON_CreateString("张三"));//添加name节点 printf("%s\n", cJSON_Print(root)); return 0; }
要使用json对象,就得创建json对象!再在其中添加键值对。
cJson简直是简单上手的第三方库。官网下载的文件中也包含了充足的示例程序,非常好!
笔者曾经亲测过,在stm32F103和stm32F411上都可以跑这个库,实现串口收发json数据包。