桌面天气预报系统(二)

常持正念方圆梦;不忘初心总是春。

1

前言

紧接着上一篇桌面天气预报系统(一),这一篇讲天气预报的数据从哪里来?天气数据是什么格式?怎么解析得到有用的天气数据?

2

天气数据从哪来?

天气数据可以从一些专门做天气预报的网站获取,如心知天气、和风天气等。小编选择的是心知天气(https://www.seniverse.com/)。网站首页如下:

我们是通过其API密钥才能获取得到其天气数据,而只有注册的用户才拥有API密钥,所以必须得注册,可以点击右上角进行注册。

3

天气数据是什么格式?

登录心知天气网站之后,点击菜单导航中的“数据”->“常规数据”即可查看“API文档”。在API文档页面的左侧可看到一些可查看的条目,如:

可点击“天气实况”查看其相关说明,可以看到其天气数据格式如下图所示:

这就是JSON格式的数据,不了解JSON的朋友可查看小编的上一篇文章JSON的简单认识进行简单地认识。

4

如何解析得到有用的数据?

从上图中的JSON格式天气数据包中我们可以看出:我们需要用到的数据就是冒号后面字符串数据,这些数据是我们需要获取并显示到屏幕上的数据。

那么,我们该怎么从这一堆JSON格式数据中解析出冒号后面的字符串呢?并且,这个系统是基于单片机的天气预报系统。而单片机使用C语言进行编程开发的,所以我们得使用C语言对这些JSON天气数据包进行解析。

其实,大神们已经写了一些专门解析JSON数据包的C语言库,即第三方库。关于这个CJSON库小编已经下载好了,可在后台回复关键字:CJSON库获取。

只要把cJSON.ccJSON.h放到工程主程序所在目录,然后在主程序中包含头文件cJSON.h即可引入该库。

5

代码及解释

程序代码如下:

/*----------------------------------------------------------------------------------------
 
 Program Explain:解析JSON天气数据包now.json(天气实况)
   Create Date:2017.12.6 by lzn
 微信公众号:zhengnian-2018
----------------------------------------------------------------------------------------*/

//1、数据来源:心知天气(api.seniverse.com)
//2、获取方法:GET https://api.seniverse.com/v3/weather/now.json?key=2owqvhhd2dd9o9f9&location=beijing&language=zh-Hans&unit=c
//3、返回的数据范例见文件test.txt

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cJSON.h"

//函数声明
int cJSON_WeatherParse(char *JSON);

/*********************************************************************************
* 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;
 int i;
 
 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);  //解析天气数据
 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)
{
 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("\n-------------------------------location-----------------------------\n");
         //匹配子对象1成员"id"
         if((item = cJSON_GetObjectItem(subobject,"id")) != NULL)  
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象1成员"name"
         if((item = cJSON_GetObjectItem(subobject,"name")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象1成员"country"
         if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象1成员"timezone"
         if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象1成员"timezone_offset"
         if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
       }
       /* 匹配子对象2 */
       if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
       {
         printf("---------------------------------now-------------------------------\n");
         //匹配子对象2成员"text"
         if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"code"
         if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"temperature"
         if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"feels_like"
         if((item = cJSON_GetObjectItem(subobject,"feels_like")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"pressure"
         if((item = cJSON_GetObjectItem(subobject,"pressure")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"humidity"
         if((item = cJSON_GetObjectItem(subobject,"humidity")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"visibility"
         if((item = cJSON_GetObjectItem(subobject,"visibility")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"wind_direction"
         if((item = cJSON_GetObjectItem(subobject,"wind_direction")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"wind_speed"
         if((item = cJSON_GetObjectItem(subobject,"wind_speed")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"wind_scale"
         if((item = cJSON_GetObjectItem(subobject,"wind_scale")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"clouds"
         if((item = cJSON_GetObjectItem(subobject,"clouds")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
         
         //匹配子对象2成员"dew_point"
         if((item = cJSON_GetObjectItem(subobject,"dew_point")) != NULL)
         {
           printf("%s : %s\n",item->string,item->valuestring);
         }
       }
       /* 匹配子对象3 */
       if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
       {
         printf("----------------------------last_update----------------------------\n");
         printf("%s : %s\n\n",subobject->string,subobject->valuestring);
       }
     }
   }
 }
 
 cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
 
 return 0;
}

该程序代码可在后台回复关键字:JSON解析,即可获取

下面来看我们的解析函数:int cJSON_WeatherParse(char *JSON)

首先使用数据类型cJSON声明一系列指针变量,cJSON是一个结构体,可在cJSON.h文件里查看,其具体内容如下:

typedef struct cJSON
{
 struct cJSON *next;  /*遍历数组或对象链的前后链表指针*/
 struct cJSON *prev;   /*遍历数组或对象链的前向链表指针*/
 struct cJSON *child;  /*数组或对象的孩子节点*/
 int type;             /*key的类型*/
 char *valuestring;    /*字符串值*/
 int valueint;         /*整数值*/
 double valuedouble;   /*浮点数值*/
 char *string;         /*key的名字*/
} cJSON;

解析函数里主要用到以下函数:

cJSON*cJSON_Parse(const char *value);

该函数用来解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。

cJSON_GetObjectItem(cJSON *object,const char *string);

该函数可从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。

cJSON_GetArraySize(const cJSON *array);

该函数可获取数组中元素个数。

cJSON_GetArrayItem(const cJSON *array, int index);

该函数可获取数组中的内容。

cJSON_Delete(cJSON *c); 

该函数用来释放cJSON_Parse函数内部申请的堆内存。

我们的解析函数主要运用多次cJSON_GetObjectItem来匹配各对象成员,然后取出各个键值对的值valuestring。

怎么测试这个解析函数呢?小编使用一个now.txt文本保存示例的JSON格式天气数据,然后调用解析函数进行解析。now.txt中的内容如下:

如图,小编已把天气示例数据中为中文的数据全改为了英文,确保解析时不会产生乱码,至于为什么是乱码以及如何解决乱码问题后续再进行讲解。

先来看程序的运行结果:

可见,解析完全正确!解析结果中冒号后面的数据就是我们可以选择使用的数据。这是解析当天的天气实况数据,解析未来几天的天气数据包或是其它天气数据包的方法都是类似的。

以上就是关于JSON格式天气数据包的解析过程,谢谢!

(0)

相关推荐

  • for循环爬取评论数据

    import time import requests import json import openpyxl '''#for循环 for i in range(3): print(i) time.s ...

  • cJSON库的安装与使用

    介绍 cJSON 库是C语言中的最常用的 JSON 库.github 地址是 https://github.com/DaveGamble/cJSON . 安装 环境是 Ubuntu 16.04.需要先 ...

  • 智能桌面天气预报系统(一)

    智能桌面天气预报系统(一)

  • 智能桌面天气预报系统(三)

    常持正念方圆梦:不忘初心总是春. 1 前言 智能桌面天气预报系统(一) 智能桌面天气预报系统(二) 紧接着前两篇文章,今天介绍的是系统的GUI设计,该作品很重要的一部分就是显示部分.显示方案有哪些呢? ...

  • 智能桌面天气预报系统(四)

    常持正念方圆梦:不忘初心总是春. 1 前言 智能桌面天气预报系统(一) 智能桌面天气预报系统(二) 智能桌面天气预报系统(三) 紧接着前三篇文章,今天介绍windows下与天气服务器通信的测试方法.每 ...

  • 智能桌面天气预报系统(终)

    常持正念方圆梦:不忘初心总是春. 1 前言 智能桌面天气预报系统(一) 智能桌面天气预报系统(二) 智能桌面天气预报系统(三) 智能桌面天气预报系统(四) 这是关于这个智能天气预报系统的最后一篇分享啦 ...

  • 通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解

    曾宇平 dotNET跨平台 今天 首先感谢张队@geffzhang公众号转发了上一篇文章,希望广大.neter多多推广dapr,让云原生更快更好的在.net这片土地上落地生根. 书接上回通过Dapr实 ...

  • 越野跑必备知识|分层穿衣系统二保暖层

    学越野跑·找V越野 看似简单的穿衣,其实环环相扣,紧密结合.有的时候感觉穿了很多,为什么还会失温?看似穿了很少,为什么还会因为大量出汗而脱水?其实都和穿衣有关系. 今天我们说下第二层中间层 保暖层也叫 ...

  • Go实现海量日志收集系统(二)

    51Reboot 将在 2020.1.16日 21:00 为您带来分享主题<大佬教你如何从 ES 初学者到 ES专家>直播链接(提前报名):https://ke.qq.com/course ...

  • 强大的桌面收纳系统-Alexander Kanygin(俄罗斯)

    你可能第一眼看不出它是什么.它其实是由来自St.Petersburg(俄罗斯圣彼得堡)的产品设计师兼建筑师Alexander Kanygin的工作室所设计的一款兼具多功能的桌面收纳产品. Alexan ...

  • 系统二次开发中设定了一套完整的审批流程,应该怎样拆分功能点呢?

    问:一个公安二次开发的系统中第五点描述如下:场所申报包括场所新增.场所启用.场所变更.场所停用.由法治人员发起,经世局审批后报省厅.需上传的信息有:名称.地址.管理人.联系方式.IP地址.功能室数量. ...