JSON简述

JSON(JavaScript Object Notation) JavaScript 对象表示法,是一种轻量级的数据交换格式。类似于XML。

基础结构

JSON基于两种结构(即由两种结构组成:对象(键值对集合)和数组):
  • “名称/值”对的集合(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 with cJSON_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 with cJSON_IsFalse): Represents a false boolean value. You can also check for boolean values in general with cJSON_IsBool.
  • cJSON_True (check with cJSON_IsTrue): Represents a true boolean value. You can also check for boolean values in general with cJSON_IsBool.
  • cJSON_NULL (check with cJSON_IsNull): Represents a null value.
  • cJSON_Number (check with cJSON_IsNumber): Represents a number value. The value is stored as a double in valuedouble and also in valueint. If the number is outside of the range of an integer, INT_MAX or INT_MIN are used for valueint.
  • cJSON_String (check with cJSON_IsString): Represents a string value. It is stored in the form of a zero terminated string in valuestring.
  • cJSON_Array (check with cJSON_IsArray): Represent an array value. This is implemented by pointing child to a linked list of cJSON items that represent the values in the array. The elements are linked together using next and prev, where the first element has prev.next == NULL and the last element next == NULL.
  • cJSON_Object (check with cJSON_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 in string.
  • cJSON_Raw (check with cJSON_IsRaw): Represents any kind of JSON that is stored as a zero terminated array of characters in valuestring. 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 that child points to and/or valuestring is not owned by this item, it is only a reference. So cJSON_Delete and other functions will only deallocate this item, not its child/valuestring.
  • cJSON_StringIsConst: This means that string points to a constant string. This means that cJSON_Delete and other functions will not try to deallocate string.

该网站一个示例,保存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

2. http://www.json.org

3. http://www.json.org/fatfree.html

4. JSON 数据格式

5. cJSON github

6. JSON构造/解析(by C)---cJSON和json-c

7. JSON C库的使用

8. JSON在线解析及格式化验证 - JSON.cn

9. struct2json

posted @ 2017-05-13 10:33  yuxi_o  阅读(1114)  评论(0编辑  收藏  举报