JSON及CJSON详解笔记

目录

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 数组解析


1. JSON

1.1 JSON 概述

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/

1.2 JSON 语法

JSON 语法是 JavaScript 语法的子集。

  • 对象表示为键值对
  • 数据由逗号分隔
  • 大括号保存对象
  • 中括号保存数组

1.2.1 JSON 对象

对象是一个无序的“‘名称/值’对”集合。一个对象以 {左括号 开始, }右括号 结束。每个“名称”后跟一个 :冒号 ;“‘名称/值’ 对”之间使用 ,逗号 分隔。

对象可以包含多个 key/value(键/值)对。

key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。

key 和 value 中使用冒号(:)分割。

每个 key/value 对使用逗号(,)分割。

JSON及CJSON详解笔记_第1张图片

 

{ "name":"zhangsan" , "age": 30 }

使用点号(.)来访问对象的值 

var x = obj.name

1.2.2 JSON 数组

数组是值(value)的有序集合。一个数组以 [左中括号 开始, ]右中括号 结束。值之间使用 ,逗号 分隔。

数组可包含多个对象。

JSON 中数组值必须是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。

JSON及CJSON详解笔记_第2张图片


{
 "sites": [
            { "name":"百度" , "url":"www.baidu.com" }, 
            { "name":"google" , "url":"www.google.com" }, 
            { "name":"微博" , "url":"www.weibo.com" }
         ]
}

对象 "sites" 是包含三个对象的数组。每个对象代表一条关于某个网站(name、url)的记录。

1.2.3 JSON 值

值(value)可以是双引号括起来的字符串(string)、数值(number)、truefalsenull、对象(object)或者数组(array)。这些结构可以嵌套。

JSON及CJSON详解笔记_第3张图片

1.2.4 JSON 字符串

字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。

字符串(string)与C或者Java的字符串非常相似。

JSON及CJSON详解笔记_第4张图片

1.2.5 JSON 数值

数值(number)也与C或者Java的数值非常相似。可以是整型或者浮点型:数值必须以十进制表示,不支持八进制与十六进制格式。

JSON及CJSON详解笔记_第5张图片

{ "age": 30 }

1.2.6 JSON 布尔值

JSON 布尔值可以是 true 或者 false:

{ "flag":true }

1.2.7 JSON null

JSON 可以设置 null 值:


{ "value":null }

1.2.8 JSON 空白

空白可以加入到任何符号之间。 以下描述了完整的语言。

JSON及CJSON详解笔记_第6张图片

1.2.9 JSON 文件 文件

JSON 文件的文件类型是 ".json"

2. CJSON获取和移植

2.1 源码获取

如果查看过JSON 官网的可以发现,语法之后,罗列了多种语言相关的JSON支持,其中就包含SJSON,直接点击就可以跳转到相关的源码GitHUB位置。

JSON及CJSON详解笔记_第7张图片

当然亦可以直接点击下面的Github链接:https://github.com/DaveGamble/cJSON

cJSON 是一个用于解析JSON 包的C 语言库,库文件为cJSON.c 和cJSON.h, 所有的实现都在这两个文件中。

JSON及CJSON详解笔记_第8张图片

2.2 CJSON 移植

CJSON 中默认C语言库的动态内存分配与释放函数,但在嵌入式系统中明显不太适合,需要更改为具体适应操作系统的,这里以freertos为例:

官方源码:

JSON及CJSON详解笔记_第9张图片

针对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

 这样就移植好了,很简单。

3 CJSON 使用

3.1 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;
/* 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 */

 

  •  cJOSN结构体为一个双向链表,并可通过child指针访问下一层。
  • .type :变量决定数据项类型(键的类型)
  • valuestring / valueint / valuedouble: 数据项 依次表示是字符串/是整形/浮点型
  • string : 节点名称,或理解为“键(key)”

 CJSON 作为JSON格式的解析库,功能无外乎构建和解析JSON格式,采用CJSON的设备,以JSON的格式发送数据,收到JSON格式的数据,解析成可供应用识别的功能。

JSON及CJSON详解笔记_第10张图片

3.2 CJSON 构建功能

3.2.1 对象构建

创建对象,并在对象中加入相关量。


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);
}

输出结果:

JSON及CJSON详解笔记_第11张图片

 

JSON及CJSON详解笔记_第12张图片

  • cJSON_CreateObject函数可创建一个根数据项,之后便可向该根数据项中添加string或int等内容,返回的是一个 cJSON的指针,注意,在这个指针用完了以后,需要手工调用 cJSON_Delete(usr); 进行内存回收 。
  • 需要注意的是  json 格式的数据,虽然也是一个字符串的样子,但这个时候还是无法当成普通的字符串进行使用,需要调用 cJSON_PrintUnformatted(usr) 或者 cJSON_Print(usr);来将json对象转换成普通的字符串,并且都是以该json对象的根为基点。两个API的区别即是:一个是没有格式的:也就是转换出的字符串中间不会有"\n" "\t"之类的东西存在,而cJSON_Print(usr);打印出来是人看起来很舒服的格式。
  • 函数内部封装关联freertos 动态内存分配函数,所以使用vPortFree函数释放被out占用的内存空间

3.2.2 数组构建

创建一个数组,并向数组添加一个字符串和一个数字

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及CJSON详解笔记_第13张图片

3.3 CJSON 解析功能

解析的过程,其实就是构建的返过程。

3.3.1 root对象

先将普通的json串处理成json对象,也就是所谓的创建json root的过程,只有一行代码即可。

cJSON * root;

root = cJSON_Parse(js_string);

cJSON_Delete(root);

根数据对象已经转换完成,接下来就是获取对象中的关键字(key),若多层嵌套,则逐层解析,类似剥洋葱。

cJSON_Parse() 与 cJSON_Delete() 操作正常情况下,必须成对出现,否则将带来内存泄漏。

3.3.2 一层对象

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);
}

 输出结果:

JSON及CJSON详解笔记_第14张图片

3.3.3 多层对象

多层本质上一样的,只是多重复几次而已。

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;
}

输出结果:

JSON及CJSON详解笔记_第15张图片

3.3.4 数组解析


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;
}

输出结果:

JSON及CJSON详解笔记_第16张图片

 更深层次的嵌套思路一致的,在此不再赘述。

你可能感兴趣的:(嵌入式开发,JSON,CJSON)