赞
踩
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
在 JS 语言中,一切都是对象。 因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:
● 对象表示为键值对
● 数据由逗号分隔
● 花括号保存对象
● 方括号保存数组
JSON 键值对是用来保存 JS 对象的一种方式,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:
{"firstName": "Json"}
JSON 接口位于 ESP8266_NONOS_SDK/include/json/jsonparse.h 和 jsontree.h。
// json.h
#define JSON_TYPE_ARRAY '[' // 数组类型
#define JSON_TYPE_OBJECT '{' // 对象类型
#define JSON_TYPE_PAIR ':' // 键值对类型
#define JSON_TYPE_PAIR_NAME 'N' /* for N:V pairs */
#define JSON_TYPE_STRING '"'
#define JSON_TYPE_INT 'I'
#define JSON_TYPE_NUMBER '0'
#define JSON_TYPE_ERROR 0
#define JSON_TYPE_CALLBACK 'C' // 回调类型
// jsontree.h /*------------------------- 生成一个JSON键值对 -------------------------*/ // 第一个参数是键名,第二个参数是键值 #define JSONTREE_PAIR(name, value) {(name), (struct jsontree_value *)(value)} /*------------------------- 生成一个回调指针 -------------------------*/ // 第一个参数JSON输出回调,第二个JSON输入回调,哪个没有就填NULL #define JSONTREE_CALLBACK(output, set) {JSON_TYPE_CALLBACK, (output), (set)} /*------------------------- 生成一个JSON树的对象 -------------------------*/ // JSONTREE_OBJECT(name, ...) 第一个参数是该对象的名称 #define JSONTREE_OBJECT(name, ...) \ static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ static struct jsontree_object name = { \ JSON_TYPE_OBJECT, \ sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ jsontree_pair_##name } /*------------------------- 生成一个JSON键值对数组 -------------------------*/ #define JSONTREE_PAIR_ARRAY(value) (struct jsontree_value *)(value) /*------------------------- 生成一个JSON数组 -------------------------*/ #define JSONTREE_ARRAY(name, ...) \ static struct jsontree_value* jsontree_value_##name[] = {__VA_ARGS__}; \ static struct jsontree_array name = { \ JSON_TYPE_ARRAY, \ sizeof(jsontree_value_##name)/sizeof(struct jsontree_value*), \ jsontree_value_##name }
以ESP8266_NONOS_SDK-2.1.0/example/IoT_Demo目录下 user_webserver.c 中 wifi_station 参数设置为例。
JSON树结构图:
/****************************************************************************** * FunctionName : wifi_station_get * Description : set up the station paramer as a JSON format * Parameters : js_ctx -- A pointer to a JSON set up * Returns : result *******************************************************************************/ LOCAL int ICACHE_FLASH_ATTR wifi_station_get(struct jsontree_context *js_ctx) { const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); // 获取JSON树参数 struct ip_info ipconfig; // 定义一个IP信息结构体 uint8 buf[20]; os_bzero(buf, sizeof(buf)); // 清空数组 wifi_station_get_config(sta_conf); // 查询Wi-Fi Station接口的当前配置参数 wifi_get_ip_info(STATION_IF, &ipconfig); // 查询Wi-Fi Station接口的IP地址 if (os_strncmp(path, "ssid", 4) == 0) { // 搜索到有"ssid"这个字符串 jsontree_write_string(js_ctx, sta_conf->ssid); // 将Station接口中ssid这个参数的字符串写入JSON树 } else if (os_strncmp(path, "password", 8) == 0) { // 以下操作同上...... jsontree_write_string(js_ctx, sta_conf->password); } else if (os_strncmp(path, "ip", 2) == 0) { os_sprintf(buf, IPSTR, IP2STR(&ipconfig.ip)); jsontree_write_string(js_ctx, buf); } else if (os_strncmp(path, "mask", 4) == 0) { os_sprintf(buf, IPSTR, IP2STR(&ipconfig.netmask)); jsontree_write_string(js_ctx, buf); } else if (os_strncmp(path, "gw", 2) == 0) { os_sprintf(buf, IPSTR, IP2STR(&ipconfig.gw)); jsontree_write_string(js_ctx, buf); } return 0; } LOCAL struct jsontree_callback wifi_station_callback = JSONTREE_CALLBACK(wifi_station_get, wifi_station_set); // 第一个回调函数用于生成JSON数据格式,第二个回调函数用于解析JSON格式数据(本部分不列出) JSONTREE_OBJECT(get_station_config_tree, JSONTREE_PAIR("ssid", &wifi_station_callback), JSONTREE_PAIR("password", &wifi_station_callback)); JSONTREE_OBJECT(ip_tree, JSONTREE_PAIR("ip", &wifi_station_callback), JSONTREE_PAIR("mask", &wifi_station_callback), JSONTREE_PAIR("gw", &wifi_station_callback)); JSONTREE_OBJECT(get_station_tree, JSONTREE_PAIR("Connect_Station", &get_station_config_tree), JSONTREE_PAIR("Ipinfo_Station", &ip_tree)); JSONTREE_OBJECT(get_wifi_station_info_tree, JSONTREE_PAIR("Station", &get_station_tree));
这里生成的JSON是:
"Station" :
{
"Connect_Station" :
{
"ssid" : "xxxx" ,
"password" : "xxxx"
} ,
"Ipinfo_Station" :
{
"ip" : "xxxx" ,
"mask" : "xxxx" ,
"gw" : "xxxx"
}
}
"Station" 是用来给后面调用生成Json数据格式的,传输时不存在,即:
"Connect_Station" :{"ssid" : "xxxx" ,"password" : "xxxx"} ,"Ipinfo_Station" :{"ip" : "xxxx" ,"mask" : "xxxx" ,"gw" : "xxxx"}
/****************************************************************************** * FunctionName : json_send * Description : processing the data as json format and send to the client or server * Parameters : arg -- argument to set for client or server * ParmType -- json format type * Returns : none *******************************************************************************/ LOCAL void ICACHE_FLASH_ATTR json_send(void *arg, ParmType ParmType) { char *pbuf = NULL; pbuf = (char *)os_zalloc(2048); switch (ParmType) { case WIFI: json_ws_send((struct jsontree_value *)&get_wifi_station_info_tree, "Station", pbuf); break; default : break; } data_send(ptrespconn, true, pbuf); // TCP发送数据 os_free(pbuf); // 释放内存 pbuf = NULL; }
这里有个 json_ws_send 函数,就是生成JSON数据格式字符串,然后给data_send函数TCP发送出去
/****************************************************************************** * FunctionName : json_ws_send * Description : set up the JSON format tree for string * Parameters : tree -- A pointer to the JSON format tree * path -- A pointer to the JSON format tree's path * pbuf -- A pointer for the data sent * Returns : none *******************************************************************************/ void ICACHE_FLASH_ATTR json_ws_send(struct jsontree_value *tree, const char *path, char *pbuf) { struct jsontree_context json; /* maxsize = 128 bytes */ json_buf = (char *)os_malloc(jsonSize); /* reset state and set max-size */ /* NOTE: packet will be truncated at 512 bytes */ pos = 0; size = jsonSize; json.values[0] = (struct jsontree_value *)tree; jsontree_reset(&json); // 设置JSON树 find_json_path(&json, path); // 查找JSON格式树路径 json.path = json.depth; json.putchar = json_putchar; while (jsontree_print_next(&json) && json.path <= json.depth); // 不断获取 JSON 树下⼀个元素 json_buf[pos] = 0; os_memcpy(pbuf, json_buf, pos); os_free(json_buf); }
以ESP8266_NONOS_SDK-2.1.0/example/IoT_Demo目录下 user_webserver.c 中 switch 参数设置为例。
/****************************************************************************** * FunctionName : status_get * Description : set up the device status as a JSON format * Parameters : js_ctx -- A pointer to a JSON set up * Returns : result *******************************************************************************/ LOCAL int ICACHE_FLASH_ATTR status_get(struct jsontree_context *js_ctx) { if (user_plug_get_status() == 1) { // 获取继电器状态 jsontree_write_int(js_ctx, 1); } else { jsontree_write_int(js_ctx, 0); } return 0; }
生成JSON格式:
"status" :0/1
LOCAL int ICACHE_FLASH_ATTR jsonTree_get(struct jsontree_context *js_ctx) { const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); //生成"String":"data" if (os_strncmp(path, "String", os_strlen("String")) == 0) { jsontree_write_string(js_ctx, "data"); //生成"Integer":1 } else if (os_strncmp(path, "Integer", os_strlen("Integer")) == 0) { jsontree_write_int(js_ctx, 1); //生成"Array":[0,1,2] } else if (os_strncmp(path, "Array", os_strlen("Array")) == 0) { int array[3] = {0,1,2}; jsontree_write_atom(js_ctx, "["); jsontree_write_int_array(js_ctx, array, 3); jsontree_write_atom(js_ctx, "]"); } return 0; }
生成JSON格式:
"String": "data",
"Integer": 1,
"Array": [0, 1, 2]
LOCAL int ICACHE_FLASH_ATTR jsonArray_get(struct jsontree_context *js_ctx) { const char *path = jsontree_path_name(js_ctx, js_ctx->depth - 1); if (os_strncmp(path, "K1", os_strlen("K2")) == 0) { jsontree_write_string(js_ctx, "D1"); } else if (os_strncmp(path, "K2", os_strlen("K2")) == 0) { jsontree_write_string(js_ctx, "D2"); } else if (os_strncmp(path, "K3", os_strlen("K3")) == 0) { jsontree_write_string(js_ctx, "D3"); } return 0; } //初始化一个Json数据回调函数 //JSONTREE_CALLBACK第一个参数为生成Json数据的函数指针,第二个为获取Json数据的函数指针 LOCAL struct jsontree_callback jsonArrayCallback = JSONTREE_CALLBACK(jsonArray_get, NULL); JSONTREE_OBJECT(jsonArrayData, JSONTREE_PAIR("K1", &jsonArrayCallback), JSONTREE_PAIR("K2", &jsonArrayCallback), JSONTREE_PAIR("K3", &jsonArrayCallback)); JSONTREE_ARRAY(jsonArray, JSONTREE_PAIR_ARRAY(&jsonArrayData), JSONTREE_PAIR_ARRAY(&jsonArrayData), JSONTREE_PAIR_ARRAY(&jsonArrayData)); LOCAL struct jsontree_callback jsonCallback = JSONTREE_CALLBACK(jsonTree_get, NULL); JSONTREE_OBJECT(jsonObject, JSONTREE_PAIR("String", &jsonCallback), JSONTREE_PAIR("Integer", &jsonCallback), JSONTREE_PAIR("JsonArray", &jsonArray));
生成JSON格式:
"String": "data", "Integer": 1, "JsonArray": [ { "K1": "D1", "K2": "D2", "K3": "D3" }, { "K1": "D1", "K2": "D2", "K3": "D3" }, { "K1": "D1", "K2": "D2", "K3": "D3" } ]
以ESP8266_NONOS_SDK-2.1.0/example/IoT_Demo目录下 user_webserver.c 中 wifi_station 参数设置为例。
LOCAL void ICACHE_FLASH_ATTR webserver_recv(void *arg, char *pusrdata, unsigned short length) { ... ... else if (os_strcmp(pURL_Frame->pFilename, "wifi") == 0) { if (pParseBuffer != NULL) { struct jsontree_context js; ... jsontree_setup(&js, (struct jsontree_value *)&wifi_req_tree, json_putchar); // ⽣成JSON格式数据树 json_parse(&js, pParseBuffer); // 解析JSON格式数据 ... } } }
这里有个 json_parse 函数,就是解析JSON格式数据
/****************************************************************************** * FunctionName : json_parse * Description : parse the data as a JSON format * Parameters : js_ctx -- A pointer to a JSON set up * ptrJSONMessage -- A pointer to the data * Returns : none *******************************************************************************/ void ICACHE_FLASH_ATTR json_parse(struct jsontree_context *json, char *ptrJSONMessage) { /* Set value */ struct jsontree_value *v; struct jsontree_callback *c; struct jsontree_callback *c_bak = NULL; while ((v = jsontree_find_next(json, JSON_TYPE_CALLBACK)) != NULL) { // 查找JSON树元素 c = (struct jsontree_callback *)v; if (c == c_bak) { continue; } c_bak = c; if (c->set != NULL) { struct jsonparse_state js; jsonparse_setup(&js, ptrJSONMessage, os_strlen(ptrJSONMessage)); // JSON解析初始化 c->set(json, &js); } } }
JSON树结构图:
/****************************************************************************** * FunctionName : wifi_station_set * Description : parse the station parmer as a JSON format * Parameters : js_ctx -- A pointer to a JSON set up * parser -- A pointer to a JSON parser state * Returns : result *******************************************************************************/ LOCAL int ICACHE_FLASH_ATTR wifi_station_set(struct jsontree_context *js_ctx, struct jsonparse_state *parser) { int type; uint8 station_tree; while ((type = jsonparse_next(parser)) != 0) { // 解析 JSON 格式下⼀个元素 if (type == JSON_TYPE_PAIR_NAME) { char buffer[64]; os_bzero(buffer, 64); if (jsonparse_strcmp_value(parser, "Station") == 0) { // ⽐较解析 JSON 数据与特定字符串 station_tree = 1; } else if (jsonparse_strcmp_value(parser, "Softap") == 0) { station_tree = 0; } if (station_tree) { if (jsonparse_strcmp_value(parser, "ssid") == 0) { // ⽐较解析 JSON 数据与特定字符串 jsonparse_next(parser); jsonparse_next(parser); jsonparse_copy_value(parser, buffer, sizeof(buffer)); // 复制当前解析字符串到指定缓存 os_memcpy(sta_conf->ssid, buffer, os_strlen(buffer)); } else if (jsonparse_strcmp_value(parser, "password") == 0) { jsonparse_next(parser); jsonparse_next(parser); jsonparse_copy_value(parser, buffer, sizeof(buffer)); os_memcpy(sta_conf->password, buffer, os_strlen(buffer)); } #if ESP_PLATFORM else if (jsonparse_strcmp_value(parser, "token") == 0) { jsonparse_next(parser); jsonparse_next(parser); jsonparse_copy_value(parser, buffer, sizeof(buffer)); user_esp_platform_set_token(buffer); } #endif } } } return 0; } LOCAL struct jsontree_callback wifi_station_callback = JSONTREE_CALLBACK(wifi_station_get, wifi_station_set); // 第一个回调函数用于生成JSON数据格式(上一部分已列出),第二个回调函数用于解析JSON格式数据 JSONTREE_OBJECT(set_station_config_tree, JSONTREE_PAIR("ssid", &wifi_station_callback), JSONTREE_PAIR("password", &wifi_station_callback), JSONTREE_PAIR("token", &wifi_station_callback)); JSONTREE_OBJECT(set_station_tree, JSONTREE_PAIR("Connect_Station", &set_station_config_tree)); JSONTREE_OBJECT(set_wifi_tree, JSONTREE_PAIR("Station", &set_station_tree), JSONTREE_PAIR("Softap", &set_softap_tree)); JSONTREE_OBJECT(wifi_request_tree, JSONTREE_PAIR("Request", &set_wifi_tree)); JSONTREE_OBJECT(wifi_req_tree, JSONTREE_PAIR("wifi", &wifi_request_tree));
这里解析的JSON是:
"wifi" :
{
"Request" :
{
"Station" :
{
"Connect_Station" :
{
"ssid" : "xxxx" ,
"password" : "xxxx"
"token" : "xxxx"
}
}
}
}
• 由 Leung 写于 2018 年 12 月 15 日
• 参考:ESP8266 Non-OS SDK API参考[zj6w]
【ESP8266】使用ESP8266 NONOS SDK的JSON API
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。