把政府公開資料JSON格式資料取得,轉成物件集合,並透過LINQ對物件集合進行讀取,這樣的範例應該還蠻多人有這樣的需求,小喵就抽個空,寫一下這個範例,提供網友與未來的自己參考~
緣起
這個題目應該是很多人會遇到的,剛好一個空檔,寫個範例,提供網友們與未來的自己參考
目標
- 從政府的公開資料平台,取得天氣的資料
- 可下拉選擇地區(資料來自取得資料Distinct)
- GridView顯示2.選擇地區的相關氣象資料
- 取得2.地區的最新一筆資料,放在最新資料區
資料來源
資料由政府的公開資料平台提供,選擇資料的格式是JSON,他的網址如下:
https://opendata.epa.gov.tw/ws/Data/ATM00698/?$format=json
準備工作
Newtonsoft.JSON
由於資料的格式是JSON,因此透過Nuget,預先取得『Newtonsoft.JSON』並安裝好
分析JSON內容(JSON Parser)
直接透過瀏覽器,先呼叫一次該網址(),取得JSON內容,看齊來亂亂的不容易理解
可以透過一個線上的服務,可以搜尋關鍵字『JSON Parser』,或者直接點選以下連結進入
將瀏覽器中亂亂的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
''' <summary>
''' 地點名稱
''' </summary>
Public Property SiteName As String
''' <summary>
''' 風向
''' </summary>
Public Property WindDirection As String
''' <summary>
''' 風力
''' </summary>
Public Property WindPower As String
Public Property Gust As String
''' <summary>
''' 能見度
''' </summary>
''' <returns></returns>
Public Property Visibility As String
''' <summary>
''' 溫度
''' </summary>
''' <returns></returns>
Public Property Temperature As String
''' <summary>
''' 濕度
''' </summary>
''' <returns></returns>
Public Property Moisture As String
''' <summary>
''' 氣壓
''' </summary>
''' <returns></returns>
Public Property AtmosphericPressure As String
''' <summary>
''' 天氣描述
''' </summary>
''' <returns></returns>
Public Property Weather As String
''' <summary>
''' 單日雨量
''' </summary>
''' <returns></returns>
Public Property Rainfall1day As String
''' <summary>
''' 單位
''' </summary>
''' <returns></returns>
Public Property Unit As String
''' <summary>
''' 資料時間
''' </summary>
''' <returns></returns>
Public Property DataCreationDate As Date
End Class
取得資料
接下來就安排個按鈕,來取得相關資料,為了讓資料不要頻繁的去取得,我們可以把取得的資料放到Session中,我們新增一個畫面(WebForm)『tWeather.aspx』,並放上一個按鈕,相關程式碼如下:
tWeather.aspx
<asp:Button ID="btnGetData" runat="server" Text="取得資料" />
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
資料存取的類別
接下來,要處理資料存取的類別,這裡有三個部分要處理,分別是
- 取得地點不重複的資料
- 依據選擇的地點,傳回符合地點的相關物件集合
- 符合地點最新(日期最大)的物件
首先,為了傳回不重複地點,提供下拉選單做為資料來源,我們先新增一個地點的類別,用來回傳結果
Public Class WSiteNameInfo
Public Property SiteName As String = ""
End Class
這個把他與WeatherInfo放一起,相同檔案裡面即可。
來在,在App_Code(或者 Models)撰寫資料存取類別裡面的內容如下:
Imports Microsoft.VisualBasic
Public Class WeatherDao
''' <summary>
''' 取得地點不重複的資料並傳回
''' </summary>
''' <returns></returns>
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
''' <summary>
''' 依據傳入的地點,取得相關資料,並傳回符合的物件集合
''' </summary>
''' <param name="SiteName">地點</param>
''' <returns></returns>
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
''' <summary>
''' 依據傳入的地點,取得該地點,資料時間最大的內容,並傳回物件
''' </summary>
''' <param name="SiteName">地點</param>
''' <returns></returns>
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" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblErr" runat="server" Text=""></asp:Label>
<hr />
<asp:Button ID="btnGetData" runat="server" Text="取得資料" />
<hr />
資料總筆數:<asp:Label ID="lblCnt" runat="server" Text=""></asp:Label><br />
地區:
<asp:DropDownList ID="ddlSiteName" runat="server" DataSourceID="odsSiteName" DataTextField="SiteName" DataValueField="SiteName" AutoPostBack="True">
</asp:DropDownList>
<asp:ObjectDataSource ID="odsSiteName" runat="server" SelectMethod="GetDistinctSiteName" TypeName="WeatherDao">
</asp:ObjectDataSource>
<br />
<div id="divRecently" runat="server">
<hr />
最新天氣狀況:
<br />地點:<asp:Label ID="lblSiteName" runat="server" Text=""></asp:Label>
<br />風向:<asp:Label ID="lblWindDirection" runat="server" Text=""></asp:Label>
<br />風力:<asp:Label ID="lblWindPower" runat="server" Text=""></asp:Label>
<br />可見度:<asp:Label ID="lblVisibility" runat="server" Text=""></asp:Label>
<br />溫度:<asp:Label ID="lblTemperature" runat="server" Text=""></asp:Label>
<br />濕度:<asp:Label ID="lblMoisture" runat="server" Text=""></asp:Label>
<br />氣壓:<asp:Label ID="lblAtmosphericPressure" runat="server" Text=""></asp:Label>
<br />天氣描述:<asp:Label ID="lblWeather" runat="server" Text=""></asp:Label>
<br />單日雨量:<asp:Label ID="lblRainfall1day" runat="server" Text=""></asp:Label>
<br />資料時間:<asp:Label ID="lblDataCreationDate" runat="server" Text=""></asp:Label>
<hr />
</div>
<asp:GridView ID="gvWs" runat="server" DataSourceID="odsWs" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="SiteName" HeaderText="地點" SortExpression="SiteName" />
<asp:BoundField DataField="WindDirection" HeaderText="風向" SortExpression="WindDirection" />
<asp:BoundField DataField="WindPower" HeaderText="風力" SortExpression="WindPower" />
<asp:BoundField DataField="Visibility" HeaderText="可見度" SortExpression="Visibility" />
<asp:BoundField DataField="Temperature" HeaderText="溫度" SortExpression="Temperature" />
<asp:BoundField DataField="Moisture" HeaderText="濕度" SortExpression="Moisture" />
<asp:BoundField DataField="AtmosphericPressure" HeaderText="氣壓" SortExpression="AtmosphericPressure" />
<asp:BoundField DataField="Weather" HeaderText="天氣描述" SortExpression="Weather" />
<asp:BoundField DataField="Rainfall1day" HeaderText="單日雨量" SortExpression="Rainfall1day" />
<asp:BoundField DataField="Unit" HeaderText="資料單位" SortExpression="Unit" />
<asp:BoundField DataField="DataCreationDate" DataFormatString="{0:yyyy/MM/dd HH:mm:ss}" HeaderText="資料時間" SortExpression="DataCreationDate" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="odsWs" runat="server" SelectMethod="GetWeatherBySiteName" TypeName="WeatherDao">
<SelectParameters>
<asp:ControlParameter ControlID="ddlSiteName" Name="SiteName" PropertyName="SelectedValue" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<br />
</div>
</form>
</body>
</html>
還有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
得到的結果如下圖:
末記
回顧一下此篇有三大重點:
- 如何從公開資料(JSON)取得資料
- 如何將JSON資料轉類別
- 如何透過LINQ針對物件集合進行資料讀取篩選
提供大家與未來的小喵參考
相關程式碼,請參考以下:
https://github.com/topcattw/WebFormGetOpenDataJSON
^_^
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
- 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
Microsoft MVP Visual Studio and Development Technologies (2005~2019/6) | topcat Blog:http://www.dotblogs.com.tw/topcat |