[笔记][OpenData][JSON][Object]取得公开资料平台天气资料转物件集合,下拉显示最新资料

把政府公开资料JSON格式资料取得,转成物件集合,并透过LINQ对物件集合进行读取,这样的范例应该还蛮多人有这样的需求,小喵就抽个空,写一下这个范例,提供网友与未来的自己参考~

缘起

这个题目应该是很多人会遇到的,刚好一个空档,写个范例,提供网友们与未来的自己参考

目标

  1. 从政府的公开资料平台,取得天气的资料
  2. 可下拉选择地区(资料来自取得资料Distinct)
  3. GridView显示2.选择地区的相关气象资料
  4. 取得2.地区的最新一笔资料,放在最新资料区

资料来源

资料由政府的公开资料平台提供,选择资料的格式是JSON,他的网址如下:

https://opendata.epa.gov.tw/ws/Data/ATM00698/?$format=json

准备工作

Newtonsoft.JSON

由于资料的格式是JSON,因此透过Nuget,预先取得『Newtonsoft.JSON』并安装好

分析JSON内容(JSON Parser)

直接透过浏览器,先呼叫一次该网址(),取得JSON内容,看齐来乱乱的不容易理解

可以透过一个线上的服务,可以搜寻关键字『JSON Parser』,或者直接点选以下连结进入

http://json.parser.online.fr/

将浏览器中乱乱的JSON全选复制,然后贴到该网页中左边处,稍微等一下让他整理,就可以得到整理好的JSON内容,方便观察。另外,也顺便查看这JSON内容是否有格式上的问题。

小提醒:如果格式有问题,他会有提示。务必确认他的格式是正确的,这样下面的步骤才不会有问题做白工。

产生类别对应JSON

我们希望可以把JSON转换成『物件的集合』,转成『物件集合』后,后续处理就会方便许多,而第一步骤,就是依据JSON的内容,去撰写对应的类别(Class)

我们新增一个Class,如果您开的是『网站』项目,就在『App_Code』里面,如果是Web项目,则是在『Models』的资料夹中

选择性贴上→贴上JSON作为类别

此步骤是这一篇的重点之一,我们新增一个类别,命名为『WeatherInfo』,把浏览器中的JSON文件整个『全选复制』,点选游标到该类别编辑区的空白处,接着,点选如下图的功能

以下这部分不需要,删除

Public Class Rootobject
    Public Property Property1() As Class1
End Class

以下这部分,是我们要的,我们把他的类别名称换成我们要的,顺便把『DataCreationDate』的资料型别改成日期『Date』,最后为每个属性加上简单的说明后,变成如下:

Imports Microsoft.VisualBasic

Public Class WeatherInfo
    ''' 
    ''' 地点名称
    ''' 
    Public Property SiteName As String

    ''' 
    ''' 风向
    ''' 
    Public Property WindDirection As String
    ''' 
    ''' 风力
    ''' 
    Public Property WindPower As String

    Public Property Gust As String

    ''' 
    ''' 能见度
    ''' 
    ''' 
    Public Property Visibility As String

    ''' 
    ''' 温度
    ''' 
    ''' 
    Public Property Temperature As String

    ''' 
    ''' 湿度
    ''' 
    ''' 
    Public Property Moisture As String

    ''' 
    ''' 气压
    ''' 
    ''' 
    Public Property AtmosphericPressure As String

    ''' 
    ''' 天气描述
    ''' 
    ''' 
    Public Property Weather As String

    ''' 
    ''' 单日雨量
    ''' 
    ''' 
    Public Property Rainfall1day As String

    ''' 
    ''' 单位
    ''' 
    ''' 
    Public Property Unit As String

    ''' 
    ''' 资料时间
    ''' 
    ''' 
    Public Property DataCreationDate As Date
End Class

取得资料

接下来就安排个按钮,来取得相关资料,为了让资料不要频繁的去取得,我们可以把取得的资料放到Session中,我们新增一个画面(WebForm)『tWeather.aspx』,并放上一个按钮,相关代码如下:

tWeather.aspx

tWeather.aspx.vb

Imports System.Net.Http
Imports Newtonsoft.Json

Partial Class Weather_tWeather
    Inherits System.Web.UI.Page

    '宣告物件集合,用以存放取得的资料
    Dim oWs As List(Of WeatherInfo)

    Private Sub Weather_tWeather_Load(sender As Object, e As EventArgs) Handles Me.Load

        Me.lblErr.Text = ""
        Me.lblCnt.Text = ""

        '从Session取回物件集合
        oWs = Session("oWs")
        '如果取得的内容是空的,就先增物件集合,并放回Session
        If oWs Is Nothing Then
            oWs = New List(Of WeatherInfo)
            Session("oWs") = oWs
        End If
    End Sub

    Protected Sub btnGetData_Click(sender As Object, e As EventArgs) Handles btnGetData.Click

        '宣告HttpClient
        Dim Client As New HttpClient
        '设定连结的网址
        Dim UriWeather As String = "https://opendata.epa.gov.tw/ws/Data/ATM00698/?$format=json"
        '取得资料,传给response(HttpResponseMessage)
        Dim response As HttpResponseMessage = Client.GetAsync(UriWeather).Result
        '取得JSON的字串
        Dim jsonWs As String = response.Content.ReadAsStringAsync.Result.ToString
        '透过JsonConvert.DeserializeObject 将 JSON字串 转成物件集合
        oWs = JsonConvert.DeserializeObject(Of List(Of WeatherInfo))(jsonWs)
        Session("oWs") = oWs
    End Sub
End Class

资料存取的类别

接下来,要处理资料存取的类别,这里有三个部分要处理,分别是

  1. 取得地点不重复的资料
  2. 依据选择的地点,传回符合地点的相关物件集合
  3. 符合地点最新(日期最大)的物件

首先,为了传回不重复地点,提供下拉选单做为资料来源,我们先新增一个地点的类别,用来回传结果

Public Class WSiteNameInfo
    Public Property SiteName As String = ""
End Class

这个把他与WeatherInfo放一起,相同文件里面即可。

来在,在App_Code(或者 Models)撰写资料存取类别里面的内容如下:

Imports Microsoft.VisualBasic

Public Class WeatherDao
    ''' 
    ''' 取得地点不重复的资料并传回
    ''' 
    ''' 
    Public Function GetDistinctSiteName() As List(Of WSiteNameInfo)
        Try
            '宣告回传的地点物件集合
            Dim oSNs As New List(Of WSiteNameInfo)
            '宣告并从Session取得天气物件集合
            Dim oWs As List(Of WeatherInfo) = HttpContext.Current.Session("oWs")
            '如果不是空的
            If oWs IsNot Nothing Then
                '而且有值
                If oWs.Count > 0 Then
                    '透过LINQ,取得地点不重复的内容
                    Dim sRlt = From oW As WeatherInfo In oWs
                               Select oW.SiteName Distinct

                    '宣告地点物件
                    Dim tWN As WSiteNameInfo
                    '取得结果逐一读取出,新增地点物件,并放入回传的地点物件集合中
                    For Each s As String In sRlt
                        tWN = New WSiteNameInfo
                        tWN.SiteName = s
                        oSNs.Add(tWN)
                    Next
                End If
            End If
            '回传地点物件集合
            Return oSNs
        Catch ex As Exception
            Throw New Exception(ex.Message)
        End Try
    End Function

    ''' 
    ''' 依据传入的地点,取得相关资料,并传回符合的物件集合
    ''' 
    ''' 地点
    ''' 
    Public Function GetWeatherBySiteName(ByVal SiteName As String) As List(Of WeatherInfo)
        Try
            '宣告条件捞取结果的物件集合
            Dim oRlts As New List(Of WeatherInfo)
            '宣告并从Session取得天气物件集合
            Dim oWs As List(Of WeatherInfo) = HttpContext.Current.Session("oWs")

            '如果不是空的
            If oWs IsNot Nothing Then
                '如果传入的地点有资料
                If SiteName <> "" Then
                    '透过LINQ从物件集合捞取符合地点的资料,并转成LIST集合物件,放入回传的物件集合
                    oRlts = (From oW As WeatherInfo In oWs
                             Where oW.SiteName = SiteName
                             Select oW).ToList()
                Else
                    '没有传入地点,结果就等于是天气物件集合的全部
                    oRlts = oWs
                End If
            End If

            '回传结果
            Return oRlts
        Catch ex As Exception
            Throw New Exception(ex.Message)
        End Try
    End Function

    ''' 
    ''' 依据传入的地点,取得该地点,资料时间最大的内容,并传回物件
    ''' 
    ''' 地点
    ''' 
    Public Function GetMaxWeatherBySiteName(ByVal SiteName As String) As WeatherInfo
        Try
            '宣告捞取的结果物件集合
            Dim oRlts As List(Of WeatherInfo)
            '宣告并从Session取得天气物件集合
            Dim oWs As List(Of WeatherInfo) = HttpContext.Current.Session("oWs")
            '宣告回传的物件
            Dim oRlt As New WeatherInfo
            '如果天气集合不是空的
            If oWs IsNot Nothing Then
                '地点资料不是空的
                If SiteName <> "" Then
                    '捞取结果依据地点筛选,并依据日期由大至小排序
                    oRlts = (
                            From oW As WeatherInfo In oWs
                            Where oW.SiteName = SiteName
                            Select oW
                            Order By oW.DataCreationDate Descending
                                 ).ToList()
                    '回传的结果是捞取结果集合的第一笔(最大)
                    oRlt = oRlts.First()
                End If
            End If

            '回传结果
            Return oRlt
        Catch ex As Exception
            Throw New Exception(ex.Message)
        End Try
    End Function

End Class


到时候画面中,就可以用『ObjectDataSource』来应用这个Dao的类别,进行资料读取与筛选,资料是物件的集合『List (Of Object)』,小喵觉得最方便读取筛选的方式,就是透过『LINQ』来处理,好懂、好写、好维护。

再来,就是把画面中,下拉选单(DropDownList)、符合资料的呈现(GridView)、以及下拉选单选择地点的最新资料,做为安排。

aspx

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="tWeather.aspx.vb" Inherits="Weather_tWeather" %>






    


    


资料总笔数:
地区:

最新天气状况:
地点:
风向:
风力:
可见度:
温度:
湿度:
气压:
天气描述:
单日雨量:
资料时间:

还有CodeFile的相关内容

tWeather.aspx.vb

Imports System.Net.Http
Imports Newtonsoft.Json

Partial Class Weather_tWeather
    Inherits System.Web.UI.Page

    '宣告物件集合,用以存放取得的资料
    Dim oWs As List(Of WeatherInfo)

    Protected Sub btnGetData_Click(sender As Object, e As EventArgs) Handles btnGetData.Click

        '宣告HttpClient
        Dim Client As New HttpClient
        '设定连结的网址
        Dim UriWeather As String = "https://opendata.epa.gov.tw/ws/Data/ATM00698/?$format=json"
        '取得资料,传给response(HttpResponseMessage)
        Dim response As HttpResponseMessage = Client.GetAsync(UriWeather).Result
        '取得JSON的字串
        Dim jsonWs As String = response.Content.ReadAsStringAsync.Result.ToString
        '透过JsonConvert.DeserializeObject 将 JSON字串 转成物件集合
        oWs = JsonConvert.DeserializeObject(Of List(Of WeatherInfo))(jsonWs)
        Session("oWs") = oWs
        BindData()


    End Sub

    Private Sub Weather_tWeather_Load(sender As Object, e As EventArgs) Handles Me.Load

        Me.lblErr.Text = ""
        Me.lblCnt.Text = ""

        '从Session取回物件集合
        oWs = Session("oWs")
        '如果取得的内容是空的,就先增物件集合,并放回Session
        If oWs Is Nothing Then
            oWs = New List(Of WeatherInfo)
            Session("oWs") = oWs
        End If
    End Sub


    Private Sub BindData()
        Me.lblCnt.Text = oWs.Count.ToString()
        Me.ddlSiteName.DataBind()
        Me.gvWs.DataBind()
        divRecentlyDataBind()
    End Sub

    Private Sub divRecentlyDataBind()
        Dim dao As New WeatherDao
        Dim oW As WeatherInfo = dao.GetMaxWeatherBySiteName(Me.ddlSiteName.SelectedValue)
        If oW.SiteName <> "" Then
            divRecentlyInit()
            lblAtmosphericPressure.Text = oW.AtmosphericPressure
            lblDataCreationDate.Text = oW.DataCreationDate
            lblMoisture.Text = oW.Moisture
            lblRainfall1day.Text = oW.Rainfall1day
            lblSiteName.Text = oW.SiteName
            lblTemperature.Text = oW.Temperature
            lblVisibility.Text = oW.Visibility
            lblWeather.Text = oW.Weather
            lblWindDirection.Text = oW.WindDirection
            lblWindPower.Text = oW.WindPower
        End If
    End Sub

    Private Sub odsSiteName_Selected(sender As Object, e As ObjectDataSourceStatusEventArgs) Handles odsSiteName.Selected
        Dim tLI As New ListItem("请选择", "")
        Me.ddlSiteName.Items.Insert(0, tLI)
    End Sub

    Private Sub divRecentlyInit()
        Me.lblAtmosphericPressure.Text = ""
        Me.lblDataCreationDate.Text = ""
        Me.lblMoisture.Text = ""
        Me.lblRainfall1day.Text = ""
        Me.lblSiteName.Text = ""
        Me.lblTemperature.Text = ""
        Me.lblVisibility.Text = ""
        Me.lblWeather.Text = ""
        Me.lblWindDirection.Text = ""
        Me.lblWindPower.Text = ""
    End Sub

    Private Sub ddlSiteName_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ddlSiteName.SelectedIndexChanged
        divRecentlyDataBind()
    End Sub
End Class

得到的结果如下图:

末记

回顾一下此篇有三大重点:

  1. 如何从公开资料(JSON)取得资料
  2. 如何将JSON资料转类别
  3. 如何透过LINQ针对物件集合进行资料读取筛选

提供大家与未来的小喵参考

相关代码,请参考以下:

https://github.com/topcattw/WebFormGetOpenDataJSON

^_^

 

 


以下是签名:


Microsoft MVP
Microsoft MVP