1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。关注微信公众号【嵌入式大杂烩】,回复1024,即可免费获取!
一、基本介绍
最近做了个基于STM32的天气预报系统。通过wifi模块从心知天气(http://www.seniverse.com/)获取天气数据,其天气数据的格式为JSON格式,对于JSON格式数据的学习,可以参考博文:http://blog.csdn.net/xukai871105/article/details/32346797(这一篇为JSON格式详解)、http://blog.csdn.net/lintax/article/details/50993958(这一篇介绍如何使用cJSON库解析JSON格式数据)和http://blog.csdn.net/taiyang1987912/article/details/49862141(这一篇为cJSON库的介绍)。cJSON库的下载地址为:http://sourceforge.net/projects/cjson/files/?source=navbar。同时,要对JSON格式数据进行校验,可以使用在线工具:https://www.bejson.com/进行校验。为了避免其他因素的影响,我没有加入其他与硬件相关的c代码。所以,我必须模拟一个天气数据包来编写测试代码。我把模拟的天气实况天气数据包保存在文本文件now.txt中,如下所示:
二、代码部分
1、结构体定义
为了能更直观,更清晰的表示解析后的天气数据。我定义了三个结构体用于保存解析后得到的天气数据。结构体定义如下:
(1)子对象1结构体--Location
typedef struct
{
char id[32];
char name[32];
char country[32];
char path[64];
char timezone[32];
char timezone_offset[32];
}Location;
(2)子对象2结构体--Now
typedef struct
{
char text[32];
char code[32];
char temperature[32];
}Now;
(3)用于保存服务器返回的天气数据
typedef struct
{
Location location; //子对象1
Now now; //子对象2
char last_update[64]; //子对象3
}Results;
2、读取now.txt文本文件数据
要解析now.txt里的数据,必须先将其读取数来。相关代码语句如下:
if((fp = fopen("now.txt","rb")) == NULL)
{
printf("Open error!\n");
return 1;
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
data = (char*)malloc(len+1);
fread(data, len, 1, fp);
fclose(fp);
3、解析JSON格式天气数据
int cJSON_WeatherParse(char *JSON, Results *results)
{
cJSON *json,*arrayItem,*object,*subobject,*item;
json = cJSON_Parse(JSON); //解析JSON数据包
if(json == NULL) //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
return 1;
}
else
{
if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); //匹配字符串"results",获取数组内容
{
int size = cJSON_GetArraySize(arrayItem); //获取数组中对象个数
printf("cJSON_GetArraySize: size=%d\n",size);
if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
{
/* 匹配子对象1 */
if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
{
printf("---------------------------------subobject1-------------------------------\n");
if((item = cJSON_GetObjectItem(subobject,"id")) != NULL) //匹配子对象1成员"id"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.id,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) //匹配子对象1成员"name"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.name,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)//匹配子对象1成员"country"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.country,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"path")) != NULL) //匹配子对象1成员"path"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.path,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)//匹配子对象1成员"timezone"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.timezone,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)//匹配子对象1成员"timezone_offset"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.timezone_offset,item->valuestring,strlen(item->valuestring));
}
}
/* 匹配子对象2 */
if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
{
printf("---------------------------------subobject2-------------------------------\n");
if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)//匹配子对象2成员"text"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].now.text,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)//匹配子对象2成员"code"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].now.code,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL) //匹配子对象2成员"temperature"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].now.temperature,item->valuestring,strlen(item->valuestring));
}
}
/* 匹配子对象3 */
if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
{
printf("---------------------------------subobject3-------------------------------\n");
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",subobject->type,subobject->string,subobject->valuestring);
memcpy(results[0].last_update,item->valuestring,strlen(subobject->valuestring));
}
}
}
}
cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
return 0;
}
4、完整代码
/*----------------------------------------------------------------------------------------
Program Explain:解析JSON天气数据包now.json(天气实况)
Create Date:2017.12.6 by lzn
----------------------------------------------------------------------------------------*/
//1、数据来源:心知天气(api.seniverse.com)
//2、获取方法:GET https://api.seniverse.com/v3/weather/now.json?key=2owqvhhd2dd9o9f9&location=beijing&language=zh-Hans&unit=c
//3、返回的数据范例见文件now.txt
#include
#include
#include
#include "cJSON.h"
//子对象1结构体--Location
typedef struct
{
char id[32];
char name[32];
char country[32];
char path[64];
char timezone[32];
char timezone_offset[32];
}Location;
//子对象2结构体--Now
typedef struct
{
char text[32];
char code[32];
char temperature[32];
}Now;
//用于保存服务器返回的天气数据
typedef struct
{
Location location; //子对象1
Now now; //子对象2
char last_update[64]; //子对象3
}Results;
//函数声明
int cJSON_WeatherParse(char *JSON, Results *results);
/*********************************************************************************
* Function Name : main主函数
* Parameter : NULL
* Return Value : 0
* Function Explain :
* Create Date : 2017.12.6 by lzn
**********************************************************************************/
int main(int argc, char **argv)
{
FILE *fp;
char *data;
int len;
Results results[] = {{0}};
if((fp = fopen("now.txt","rb")) == NULL)
{
printf("Open error!\n");
return 1;
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
data = (char*)malloc(len+1);
fread(data, len, 1, fp);
fclose(fp);
printf("read file %s complete, len=%d.\n","now.txt",len);
cJSON_WeatherParse(data, results); //解析天气数据
free(data);
system("pause");
return 0;
}
/*********************************************************************************
* Function Name : cJSON_WeatherParse,解析天气数据
* Parameter : JSON:天气数据包 results:保存解析后得到的有用的数据
* Return Value : 0:成功 其他:错误
* Function Explain :
* Create Date : 2017.12.6 by lzn
**********************************************************************************/
int cJSON_WeatherParse(char *JSON, Results *results)
{
cJSON *json,*arrayItem,*object,*subobject,*item;
json = cJSON_Parse(JSON); //解析JSON数据包
if(json == NULL) //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
return 1;
}
else
{
if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); //匹配字符串"results",获取数组内容
{
int size = cJSON_GetArraySize(arrayItem); //获取数组中对象个数
printf("cJSON_GetArraySize: size=%d\n",size);
if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
{
/* 匹配子对象1 */
if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
{
printf("---------------------------------subobject1-------------------------------\n");
if((item = cJSON_GetObjectItem(subobject,"id")) != NULL) //匹配子对象1成员"id"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.id,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) //匹配子对象1成员"name"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.name,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)//匹配子对象1成员"country"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.country,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"path")) != NULL) //匹配子对象1成员"path"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.path,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)//匹配子对象1成员"timezone"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.timezone,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)//匹配子对象1成员"timezone_offset"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].location.timezone_offset,item->valuestring,strlen(item->valuestring));
}
}
/* 匹配子对象2 */
if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
{
printf("---------------------------------subobject2-------------------------------\n");
if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)//匹配子对象2成员"text"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].now.text,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)//匹配子对象2成员"code"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].now.code,item->valuestring,strlen(item->valuestring));
}
if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL) //匹配子对象2成员"temperature"
{
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(results[0].now.temperature,item->valuestring,strlen(item->valuestring));
}
}
/* 匹配子对象3 */
if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
{
printf("---------------------------------subobject3-------------------------------\n");
printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s\n",subobject->type,subobject->string,subobject->valuestring);
memcpy(results[0].last_update,item->valuestring,strlen(subobject->valuestring));
}
}
}
}
cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
return 0;
}
该代码的运行结果如下图所示:
解析得到的结果与now.txt中的有用的数据完全一致,解析成功!
三、总结
JSON格式解析的函数中,不必再使用malloc或者之后移植到单片机系统上时也无需再使用自定义的malloc再对arrayItem,object,subobject,item等cJSON型指针变量再申请内存,因为在cJSON_Parse函数内部已经有申请一整块的内存空间供整个解析过程使用,如果再多申请空间,程序在单片机里运行一段时间后可能会导致系统崩溃死机。除此之外,分享一篇让我收益良多的与单片机相关的天气预报系统的例子:http://www.openedv.com/thread-229818-1-1.html。我们都应该有开源共享的精神,互相帮助互相学习才能学得更快更好!
欢迎扫描左侧二维码关注我的微信公众号(或者搜索:zhengnian-2018)