目录
1. JSON
1.1 JSON 概述
1.2 JSON 语法
1.2.1 JSON 对象
1.2.2 JSON 数组
1.2.3 JSON 值
1.2.4 JSON 字符串
1.2.5 JSON 数值
1.2.6 JSON 布尔值
1.2.7 JSON null
1.2.8 JSON 空白
1.2.9 JSON 文件 文件
2. CJSON获取和移植
2.1 源码获取
2.2 CJSON 移植
3 CJSON 使用
3.1 CJSON 结构体
3.2 CJSON 构建功能
3.2.1 对象构建
3.2.2 数组构建
3.3 CJSON 解析功能
3.3.1 root对象
3.3.2 一层对象
3.3.3 多层对象
3.3.4 数组解析
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
JSON建构于两种结构:
“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
官方网站:http://www.json.org/
JSON 语法是 JavaScript 语法的子集。
对象是一个无序的“‘名称/值’对”集合。一个对象以 {
左括号 开始, }
右括号 结束。每个“名称”后跟一个 :
冒号 ;“‘名称/值’ 对”之间使用 ,
逗号 分隔。
对象可以包含多个 key/value(键/值)对。
key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。
key 和 value 中使用冒号(:)分割。
每个 key/value 对使用逗号(,)分割。
{ "name":"zhangsan" , "age": 30 }
使用点号(.)来访问对象的值
var x = obj.name
数组是值(value)的有序集合。一个数组以 [
左中括号 开始, ]
右中括号 结束。值之间使用 ,
逗号 分隔。
数组可包含多个对象。
JSON 中数组值必须是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。
{
"sites": [
{ "name":"百度" , "url":"www.baidu.com" },
{ "name":"google" , "url":"www.google.com" },
{ "name":"微博" , "url":"www.weibo.com" }
]
}
对象 "sites" 是包含三个对象的数组。每个对象代表一条关于某个网站(name、url)的记录。
值(value)可以是双引号括起来的字符串(string)、数值(number)、true
、false
、 null
、对象(object)或者数组(array)。这些结构可以嵌套。
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
字符串(string)与C或者Java的字符串非常相似。
数值(number)也与C或者Java的数值非常相似。可以是整型或者浮点型:数值必须以十进制表示,不支持八进制与十六进制格式。
{ "age": 30 }
JSON 布尔值可以是 true 或者 false:
{ "flag":true }
JSON 可以设置 null 值:
{ "value":null }
空白可以加入到任何符号之间。 以下描述了完整的语言。
JSON 文件的文件类型是 ".json"
如果查看过JSON 官网的可以发现,语法之后,罗列了多种语言相关的JSON支持,其中就包含SJSON,直接点击就可以跳转到相关的源码GitHUB位置。
当然亦可以直接点击下面的Github链接:https://github.com/DaveGamble/cJSON
cJSON 是一个用于解析JSON 包的C 语言库,库文件为cJSON.c 和cJSON.h, 所有的实现都在这两个文件中。
CJSON 中默认C语言库的动态内存分配与释放函数,但在嵌入式系统中明显不太适合,需要更改为具体适应操作系统的,这里以freertos为例:
官方源码:
针对freertos 修改后:
#if defined(_MSC_VER)
/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
static void * CJSON_CDECL internal_malloc(size_t size)
{
// return malloc(size);
return pvPortMalloc(size);
}
static void CJSON_CDECL internal_free(void *pointer)
{
// free(pointer);
vPortFree(pointer);
}
static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
{
// return realloc(pointer, size);
return NULL;
}
#else
#define internal_malloc pvPortMalloc
#define internal_free vPortFree
#define internal_realloc
#endif
这样就移植好了,很简单。
/* 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;
/* cJSON Types: */
#define cJSON_Invalid (0)
#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_Raw (1 << 7) /* raw json */
string : 节点名称,或理解为“键(key)”
CJSON 作为JSON格式的解析库,功能无外乎构建和解析JSON格式,采用CJSON的设备,以JSON的格式发送数据,收到JSON格式的数据,解析成可供应用识别的功能。
创建对象,并在对象中加入相关量。
void cjson_test ( void )
{
cJSON * usr;
char * out;
uint8_t stat = 0;
printf("\r\n--- CJSON Test %s---\r\n ",__TIME__);
usr = cJSON_CreateObject(); // 创建根数据对象
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddNullToObject(usr, "NULL"); // 加入null
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddTrueToObject(usr, "TURE"); // 加入ture
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddFalseToObject(usr, "FALSE"); // 加入false
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddBoolToObject(usr, "BOOL", 0); // 加入 bool
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddNumberToObject(usr, "INT_NUM", 10); // 加入 整数
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddNumberToObject(usr, "F_NUM", 9.9); // 加入浮点数
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddStringToObject(usr, "STRING", "This is string!"); // 加入字符串
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddObjectToObject(usr, "OBJECT"); // 加入对象
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddArrayToObject(usr, "ARRARY"); // 加入数组
out = cJSON_Print(usr);
// out = cJSON_PrintUnformatted(usr);
printf("%s", out);
cJSON_Delete(usr);
if(out)
vPortFree(out);
}
输出结果:
创建一个数组,并向数组添加一个字符串和一个数字
void cjson_test ( void )
{
cJSON * usr;
char * out;
uint8_t stat = 0;
printf("\r\n--- CJSON Test %s---\r\n ",__TIME__);
/* 创建根数据数组 */
usr = cJSON_CreateArray();
if (stat)
{
out = cJSON_Print(usr);
printf("\r\n%s\r\n", out);
}
cJSON_AddItemToArray(usr, cJSON_CreateString("hello cjson"));
cJSON_AddItemToArray(usr, cJSON_CreateNumber(99));
out = cJSON_Print(usr);
printf("%s", out);
cJSON_Delete(usr);
if(out)
vPortFree(out);
}
输出结果:
解析的过程,其实就是构建的返过程。
先将普通的json串处理成json对象,也就是所谓的创建json root的过程,只有一行代码即可。
cJSON * root;
root = cJSON_Parse(js_string);
cJSON_Delete(root);
根数据对象已经转换完成,接下来就是获取对象中的关键字(key),若多层嵌套,则逐层解析,类似剥洋葱。
cJSON_Parse() 与 cJSON_Delete() 操作正常情况下,必须成对出现,否则将带来内存泄漏。
CJSON中type定义完全的,正常需要先判断type再取值。
void cjson_test ( void )
{
cJSON * root, *js_name,*js_class,*js_age;
char * in_js_string = "{\"name\":\"laowang\",\"class\":\"3-2\",\"age\":10}";
printf("\r\n--- CJSON Test %s---\r\n ",__TIME__);
root = cJSON_Parse(in_js_string);
js_name = cJSON_GetObjectItem(root, "name");
js_class = cJSON_GetObjectItem(root, "class");
js_age = cJSON_GetObjectItem(root, "age");
printf("\r\nvalue(name:%s , class:%s, age:%d)\r\n", js_name->valuestring, js_class->valuestring, js_age->valueint);
printf("\r\ntpye(name:%d , class:%d, age:%d)\r\n", js_name->type, js_class->type, js_age->type);
cJSON_Delete(root);
}
输出结果:
多层本质上一样的,只是多重复几次而已。
int cjson_test ( void )
{
cJSON * root, *js_name,*js_class,*js_age, *num1,*num2;
char * in_js_string = "{\"num1\":{\"name\":\"laowang\",\"class\":\"3-2\",\"age\":10}, \"num2\":{\"name\":\"laoliu\",\"class\":\"3-1\",\"age\":11}}";
printf("\r\n--- CJSON Test %s---\r\n ",__TIME__);
root = cJSON_Parse(in_js_string);
if (!root)
{
printf("Get root object failed");
return -1;
}
num1 = cJSON_GetObjectItem(root, "num1");
if (!num1)
{
printf("Get num1 object failed");
return -1;
}
if (num1->type == cJSON_Object)
{
/* 对象 */
js_name = cJSON_GetObjectItem(num1, "name");
js_class = cJSON_GetObjectItem(num1, "class");
js_age = cJSON_GetObjectItem(num1, "age");
printf("\r\n num1(name:%s , class:%s, age:%d)\r\n", js_name->valuestring, js_class->valuestring, js_age->valueint);
}
num2 = cJSON_GetObjectItem(root, "num2");
if (!num2)
{
printf("Get num2 object failed");
return -1;
}
if (num2->type == cJSON_Object)
{
/* 对象 */
js_name = cJSON_GetObjectItem(num2, "name");
js_class = cJSON_GetObjectItem(num2, "class");
js_age = cJSON_GetObjectItem(num2, "age");
printf("\r\n num2(name:%s , class:%s, age:%d)\r\n", js_name->valuestring, js_class->valuestring, js_age->valueint);
}
cJSON_Delete(root);
return 0;
}
输出结果:
int cjson_test ( void )
{
cJSON * root,*js_lsit;
char * in_js_string = "{\"list\":[\"name\",\"class\"]}";
printf("\r\n--- CJSON Test %s---\r\n ",__TIME__);
root = cJSON_Parse(in_js_string);
if (!root)
{
printf("Get root object failed");
return -1;
}
js_lsit = cJSON_GetObjectItem(root, "list");
if (!js_lsit)
{
printf("Get js_lsit object failed");
return -1;
}
if(cJSON_Array == js_lsit->type) {
/* 获取数组大小 */
int array_size = cJSON_GetArraySize(js_lsit);
cJSON * item;
// printf("list type is array: %d \r\n", js_lsit->type);
for (size_t i = 0; i < array_size; i++)
{
/* 解析数组成员 */
item = cJSON_GetArrayItem(js_lsit, i);
printf("item(%s) type is %d\r\n",item->valuestring, item->type);
}
}
if(root)
cJSON_Delete(root);
return 0;
}
输出结果:
更深层次的嵌套思路一致的,在此不再赘述。