近期需要应用cJSON,其实多年前使用过cJSON,基本全忘记了,特此针对以前代码复习记录。
下面是一个cJSON的基本结构体
/* 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具有以下这些形式:
对象是一个无序的“‘名称/值’对”集合。一个对象以 {左括号 开始, }右括号 结束。每个“名称”后跟一个 :冒号 ;“‘名称/值’ 对”之间使用 ,逗号 分隔。
基本用法举例:
A 一个开锁命令应答的例子:CMDSet_Ack_Lock(“lock” , “ok”,door_id);
1、定义一个cJSON型指针cJSON * pJsonRoot = NULL; 创建一个cJSON对象pJsonRoot = cJSON_CreateObject();这样就建立了一个基本的cJSON object:pJsonRoot
{
“”
}
事实上cJSON可创建为单一对象Object、Raw、阵列Array、整型阵列IntArray、浮点型阵列FloatArray、字符串型阵列StringArray等,我们简单使用就用单一对象即可,其它不做探讨。
2、由于还要用到一个子对象,因此定义一个cJSON型指针cJSON * pSubJson = NULL;
创建一个cJSON对象pSubJson = cJSON_CreateObject();作为子jSON对象pSubJson
{
“”
}
3、先往子对象里面添加项目
先添加字符串{“lock”:”ok”}:cJSON_AddStringToObject(pSubJson, (const char*)cmd , (const char*)result);结果为:{“lock”:”ok”}
4、将控制结果(就是上一步子对象)作为子项目添加到pJsonRoot,项目名称
”ack”:cJSON_AddItemToObject(pJsonRoot, “ack”, pSubJson);结果为:
{
“ack”:{“lock”:”ok”}
}
5、将门锁编号(整型)添加到pJsonRoot,项目名称
”door_id”:cJSON_AddNumberToObject(pJsonRoot, “door_id”,3);结果变为:
{
“ack”:{“lock”:”ok”},
“door_id”:3
}
6、将设备编号(字符串型)添加到pJsonRoot,项目名称
”deviceid”,cJSON_AddStringToObject(pJsonRoot, “deviceid”,(const char*)PRODUCT_ID);结果变为:
{
“ack”:{“lock”:”ok”},
“door_id”:3,
“deviceid”:” 008605710100172601”
}
7、将服务端指令编号(字符串型)添加到pJsonRoot, 项目名称
”traceid”,cJSON_AddStringToObject(pJsonRoot, “traceid”,(const char*)TraceID);结果变为:
{
“ack”:{“lock”:”ok”},
“door_id”:3,
“deviceid”:” 008605710100172601”,
“traceid”:”1001”
}
8、cJSON对象内部项目组装完成后,打印为可发送的整型数组(指针)pPrintData = (INT8U*)cJSON_Print(pJsonRoot);实际为放到一段内存空间,发送后需释放内存。
9、发送CJSON_SEND(pPrintData , strlen((const char*)pPrintData));
10、删除cJSON_Delete(pJsonRoot);
11、释放内存tlsf_free(pPrintData);
B 一个同时开关多个LED灯的例子:static INT16S Led_Parse(cJSON root)
1、定义要用的cJSON格式(名称上反映出多个灯控制的指令应该是阵列格式)cJSON pJsonArray = NULL; 查询到名称”led”,pJsonArray = cJSON_GetObjectItem(root, “led”);
2、获取阵列元素数量INT16U array_size = cJSON_GetArraySize(pJsonArray);
3、然后依次获取每个元素的项目,
for(int i = 0; i < array_size; i++)
{ cJSON * ArrayItem = cJSON_GetArrayItem(pJsonArray, i);}
4、内部再定义一个用来解析的cJSON指针变量cJSON* ObjectItem = NULL;
5、依次获取阵列中的对象,ObjectItem = cJSON_GetObjectItem(ArrayItem , Led_ArrayItemKey[i]);其中Led_ArrayItemKey是预先定义好的静态变量
const char* Led_ArrayItemKey[] =
{
“led1”,
“led2”,
“led3”,
};
6、判断对象的字符串进行相应控制并且作出应答
if(ObjectItem)
{
if(strcmp(ObjectItem->valuestring , "on") == 0)
{
DTU_Drv.IO->DOSet(Led_Portx[i]);
err = CJSON_PARSE_ERR_NONE;
}
else if(strcmp(ObjectItem->valuestring , "off") == 0)
{
DTU_Drv.IO->DOReset(Led_Portx[i]);
err = CJSON_PARSE_ERR_NONE;
}
if(err == CJSON_PARSE_ERR_NONE)
CMDSet_Ack(ObjectItem->string , "ok");
else
CMDSet_Ack(ObjectItem->string , "fail");
}
C 收到数据后开始解析的步骤
1、由于需要获取整体cJSON、命令数据、控制路径数据,先定义三个cJSON指针 cJSON *pJsonRoot = NULL;cJSON *pJsonObjectItem = NULL;cJSON pJsonObject = NULL;
2、解析整个数据包,解析成cJSON格式,pJsonRoot = cJSON_Parse(pData);
3、尝试依次查询各个命令项目,若查询到,再进行后续操作
for(INT8U i = 0 ; i < sizeof(cJSON_CMD_Set)/sizeof(cJSON_CMD_Set_t) ; i++)
{
pJsonObjectItem = cJSON_GetObjectItem(pJsonRoot, (const char)cJSON_CMD_Set[i].CMD);
}
其中cJSON_CMD_Set[i].CMD已经预先进行了定义
cJSON_CMD_Set_t cJSON_CMD_Set[] =
{
//down
{"infomation" , JSON_CMD_TYPE_OBJECT , JSON_CMD_DIR_DOWN , Infomation_Parse},
{"lock" , JSON_CMD_TYPE_ARRAY , JSON_CMD_DIR_DOWN , Lock_Parse},
{"scanner" , JSON_CMD_TYPE_OBJECT , JSON_CMD_DIR_DOWN , scanner_Parse},
{"eraser" , JSON_CMD_TYPE_OBJECT , JSON_CMD_DIR_DOWN , Earser_Parse},
{"led" , JSON_CMD_TYPE_ARRAY , JSON_CMD_DIR_DOWN , Led_Parse},
{"ip" , JSON_CMD_TYPE_OBJECT , JSON_CMD_DIR_DOWN , NULL},
{"reset" , JSON_CMD_TYPE_OBJECT , JSON_CMD_DIR_DOWN , Reset_Parse},
{"factoryset" , JSON_CMD_TYPE_OBJECT , JSON_CMD_DIR_DOWN , NULL},
};
4、若查询到,再进行后续操作
if(pJsonObjectItem)
{
if(cJSON_CMD_Set[i].callback)//如果有回调函数
{
pJsonObject = cJSON_GetObjectItem(pJsonRoot, (const char*)"traceid");//查询traceid
if(pJsonObject)
strcpy(TraceID , pJsonObject->valuestring);
else
memset(TraceID , 0 ,sizeof(TraceID));
//判断命令类型是阵列还是单一对象,而后进入具体回调函数处理
if(cJSON_CMD_Set[i].Type == JSON_CMD_TYPE_ARRAY)
cJSON_CMD_Set[i].callback(pJsonRoot);
else
cJSON_CMD_Set[i].callback(pJsonObjectItem);
}
}