JSON简述
JSON(JavaScript Object Notation) JavaScript 对象表示法,是一种轻量级的数据交换格式。类似于XML。
基础结构
- “名称/值”对的集合(A collection of name/value pairs)对象。不同的编程语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
- 有序列表值(An ordered list of values)。在大部分语言中,它被实现为数组(array),矢量(vector),列表(list),序列(sequence)。
基础形式
Json有以下形式:
1. 对象(object)是一个无序的键值对集合。以{开始,以}结束,键值间用:分隔,键值对间用,分隔,key需要用引号“”括起来。
2. 数组(array)是值(value)的有序集合。一个数组以[开始,以]结束,值之间用,分割。
3. 值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、null、对象(object)或者数组(array),共7种类型。这些结构可以嵌套。
4. 字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
下图是字符串表示方法:
5. 数值(number)也与C或java数值非常相似,只是json没有2进制、8进制和16进制格式。
数据访问
json对象类似于结构体,可以用点号访问赋值。
json数组元素以0开头。
Json示例
{ "sites": [ { "name":"菜鸟教程" , "url":"www.runoob.com" }, { "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" } ] }
以javascript为例,创建var变量赋值:
var web = { "sites": [ { "name":"菜鸟教程" , "url":"www.runoob.com" }, { "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" } ] }
可通过web.sites[1].name获取字符串google。
可通过web.sites[2].name = "webo" 修改“微博”为“webo”。
JSON C解析
json常用的c解析为cJSON,只需要两个文件,cJSON.h和cJSON.c,地址:https://github.com/DaveGamble/cJSON。
ps:json与struct转换可参考: struct2json
/* The cJSON structure: */ typedef struct cJSON { struct cJSON *next; struct cJSON *prev; struct cJSON *child; int type; char *valuestring; /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ int valueint; double valuedouble; char *string; } cJSON;
An item of this type represents a JSON value. The type is stored in type
as a bit-flag (this means that you cannot find out the type by just comparing the value of type
).
/* cJSON Types: */ #define cJSON_Invalid (0) #define cJSON_Bool (1 << 0) #define cJSON_Int (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 */ #define cJSON_IsReference 256 #define cJSON_StringIsConst 512
The type can be one of the following:
cJSON_Invalid
(check withcJSON_IsInvalid
): Represents an invalid item that doesn't contain any value. You automatically have this type if you set the item to all zero bytes.cJSON_False
(check withcJSON_IsFalse
): Represents afalse
boolean value. You can also check for boolean values in general withcJSON_IsBool
.cJSON_True
(check withcJSON_IsTrue
): Represents atrue
boolean value. You can also check for boolean values in general withcJSON_IsBool
.cJSON_NULL
(check withcJSON_IsNull
): Represents anull
value.cJSON_Number
(check withcJSON_IsNumber
): Represents a number value. The value is stored as a double invaluedouble
and also invalueint
. If the number is outside of the range of an integer,INT_MAX
orINT_MIN
are used forvalueint
.cJSON_String
(check withcJSON_IsString
): Represents a string value. It is stored in the form of a zero terminated string invaluestring
.cJSON_Array
(check withcJSON_IsArray
): Represent an array value. This is implemented by pointingchild
to a linked list ofcJSON
items that represent the values in the array. The elements are linked together usingnext
andprev
, where the first element hasprev.next == NULL
and the last elementnext == NULL
.cJSON_Object
(check withcJSON_IsObject
): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys instring
.cJSON_Raw
(check withcJSON_IsRaw
): Represents any kind of JSON that is stored as a zero terminated array of characters invaluestring
. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON.
Additionally there are the following two flags:
cJSON_IsReference
: Specifies that the item thatchild
points to and/orvaluestring
is not owned by this item, it is only a reference. SocJSON_Delete
and other functions will only deallocate this item, not itschild
/valuestring
.cJSON_StringIsConst
: This means thatstring
points to a constant string. This means thatcJSON_Delete
and other functions will not try to deallocatestring
.
该网站一个示例,保存json数据:
{ "name": "Awesome 4K", "resolutions": [ { "width": 1280, "height": 720 }, { "width": 1920, "height": 1080 }, { "width": 3840, "height": 2160 } ] }
#include <stdio.h> #include "cJSON.h" char *create_monitor(void) { const unsigned int resolution_numbers[3][2] = { {1280, 720}, {1920, 1080}, {3840, 2160} }; char *string = NULL; cJSON *monitor = NULL; cJSON *name = NULL, *resolutions = NULL, *resolution = NULL; cJSON *width = NULL, *height = NULL; monitor = cJSON_CreateObject(); if(monitor == NULL){ return NULL; } /* name = cJSON_CreateString("Awesome 4K"); if(name == NULL){ goto end; } cJSON_AddItemToObject(monitor, "name", name); */ if(cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL){ goto end; } /* resolutions = cJSON_CreateArray(); if(resolutions == NULL){ goto end; } cJSON_AddItemToObject(monitor, "resolutions", resolutions); */ resolutions = cJSON_AddArrayToObject(monitor, "resolutions"); if(resolutions == NULL){ goto end; } for(int index = 0; index < (sizeof(resolution_numbers)/sizeof(resolution_numbers[0])); index++){ resolution = cJSON_CreateObject(); if(resolution == NULL){ goto end; } cJSON_AddItemToArray(resolutions, resolution); /* width = cJSON_CreateNumber(resolution_numbers[index][0]); if(width == NULL){ goto end; } cJSON_AddItemToObject(resolution, "width", width); height = cJSON_CreateNumber(resolution_numbers[index][1]); if(height == NULL){ goto end; } cJSON_AddItemToObject(resolution, "height", height); */ if(cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0])== NULL){ goto end; } if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL){ goto end; } } // string = cJSON_PrintUnformatted(monitor); string = cJSON_Print(monitor); if(string == NULL){ printf("Failed to print monitor\n"); } end: cJSON_Delete(monitor); return string; } int supports_full_hd(const char * const monitor) { const cJSON *resolution = NULL; const cJSON *resolutions = NULL; cJSON *monitor_json = NULL; const cJSON *name = NULL; int status = 0; monitor_json = cJSON_Parse(monitor); if(monitor_json == NULL){ const char *error_ptr = cJSON_GetErrorPtr(); if(error_ptr != NULL){ printf("Error before: %s\n", error_ptr); } status = 0; goto end; } name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name"); if(cJSON_IsString(name) && (name->valuestring != NULL)){ printf("checking monitor \"%s\"\n", name->valuestring); } resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions"); cJSON_ArrayForEach(resolution, resolutions){ cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width"); cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height"); if(!cJSON_IsNumber(width) || !cJSON_IsNumber(height)){ status = 0; goto end; } if((width->valueint == 1920 && height->valueint == 1080)){ status = 1; goto end; } } end: cJSON_Delete(monitor_json); return status; } int main(int argc, char *argv[]) { char *show = NULL; if((show = create_monitor()) != NULL){ printf("create JSON:\n%s\n", show); if(supports_full_hd(show)){ printf("device support hd\n"); } cJSON_free(show); } return 0; }
XML与JSON比较
* 格式简单易于解析和生成,内容灵活。
同一信息JSON和XML表示示例:
JSON表示方法:
{ "author" : "Gambardella, Matthew", "title" : "XML Developer's Guide", "genre" : "Computer" }
XML示例:
<book> <author>Gambardella, Matthew</author> <title>XML Developer's Guide</title> <genre>Computer</genre> </book>
对于XML数据,其本身是一个DOM Tree的数据结构,开发人员必须使用DOM API来访问和处理XML数据;而且DOM在各个浏览器中的实现也不尽相同,所以针对XML DOM的编程方式会变的更为复杂,另外对于XMLDOM,浏览器目前还不支持类似于XPath这样的查询语句,显然对于XMLDOM数据的访问显然要比访问JSON复杂多了。
* 性能
从数据传输量上来看JSON显然要优于XML,JSON更轻量级一些,它没有像XML那样多的Open和Closing标记。同时在对数据的解析速度上,JSON也要优于XML。
* 安全性
XML要强于JSON。
* 序列化
XML要比JSON方便。
JSON工具
命令行终端格式化显示json串:python -m json.tool {}
JSON C++解析
jsoncpp 参考:C++ 之 C++ 操作 json 文件(C++读写json文件)及jsoncpp配置详解
struct和json互转
使用struct2json库,参考demo代码。
#include <stdio.h> #include <stdint.h> #include "s2j.h" typedef struct { char name[16]; } hometown_t; typedef struct { uint8_t id; double weight; uint8_t score[8]; char name[10]; hometown_t hometown; } student_t; static void *json_to_struct(cJSON * json_obj) { s2j_create_struct_obj(struct_student, student_t); s2j_struct_get_basic_element(struct_student, json_obj, int, id); s2j_struct_get_basic_element(struct_student, json_obj, double, weight); s2j_struct_get_array_element(struct_student, json_obj, int, score); s2j_struct_get_basic_element(struct_student, json_obj, string, name); s2j_struct_get_struct_element(struct_hometown, struct_student, json_hometown, json_obj, hometown_t, hometown); s2j_struct_get_basic_element(struct_hometown, json_hometown, string, name); return struct_student; } static cJSON *struct_to_json(void *struct_obj) { student_t *struct_student = (student_t*)struct_obj; s2j_create_json_obj(json_student); s2j_json_set_basic_element(json_student, struct_student, int, id); s2j_json_set_basic_element(json_student, struct_student, double, weight); s2j_json_set_array_element(json_student, struct_student, int, score, 8); s2j_json_set_basic_element(json_student, struct_student, string, name); s2j_json_set_struct_element(json_hometown, json_student, struct_hometown, struct_student, hometown_t, hometown); s2j_json_set_basic_element(json_hometown, struct_hometown, string, name); return json_student; } int main(void) { char *string = NULL; cJSON *str_json = NULL; static student_t original_student_obj = { .id = 100, .weight = 60.5, .score = {1,2, 3, 4, 5, 6, 7, 8}, .name = "wang", .hometown.name = "China", }; cJSON *json_student = struct_to_json(&original_student_obj); student_t *dest_student_obj = json_to_struct(json_student); if(memcmp(&original_student_obj, dest_student_obj, sizeof(student_t))){ printf("Convert failed!\n"); } else { printf("Convert OK!\n"); string = cJSON_Print(json_student); printf("json##:%s\n", string); str_json = cJSON_Parse(string); if(str_json == NULL){ const char *error_ptr = cJSON_GetErrorPtr(); if(error_ptr != NULL){ printf("Parse json string error: %s\n", error_ptr); goto end; } } char *new_string = cJSON_Print(str_json); printf("new json##:%s\n", new_string); cJSON_free(new_string); } end: cJSON_Delete(str_json); s2j_delete_json_obj(json_student); s2j_delete_struct_obj(dest_student_obj); cJSON_free(string); return 0; }
gcc test.c cJSON/*.c struct2json/src/*.c -I cJSON/ -I struct2json/inc/ -o main
valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes --show-mismatched-frees=yes ./main
参考:
1. http://www.runoob.com/json/json-tutorial.html
3. http://www.json.org/fatfree.html
4. JSON 数据格式
5. cJSON github
6. JSON构造/解析(by C)---cJSON和json-c
7. JSON C库的使用
9. struct2json