作者hoyunxian (WildDagger)
看板WindowsPhone
標題[教學][程式開發] 在WP8上讀取XML/JSON的方法(3)
時間Thu Feb 6 23:41:37 2014
承接上篇的(2),接收到網路資料後,就該開始解析了。
這邊先講JSON的解析:
有點遺憾的是,雖然Windows 8/8.1有內建Windows.Data.Json,
可以直接解析JSON,但是WP8並沒有這個namespace可用
因此這個時候又得求助NuGet了。
同樣在管理NuGet套件的視窗中,以JSON搜尋,
應該可以找到名為Json.NET的套件
(名稱很像的不少,本篇教學文用的套件識別碼是Newtonsoft.Json,要找對喔)
總之找到後裝下去吧,畢竟不裝要直接硬幹的話正規表達式可是讓人很頭疼的
找對之後,在開始解析前要先記得在開頭加上
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
這兩行來引用這個函式庫,
接著也要注意你的資料結構,
一般而言政府的公開平台傳回來的都會是一個物件陣列
所以千萬不要用JObject的Parse指令來解析,系統會狠狠打你一巴掌的
得到的是陣列資料的話,請用JArray的Parse:
JArray dataArray = JArray.Parse(content);
這樣一行執行下去,程式就會自動將字串解讀成JSON物件陣列了
接著可以用Foreach來取得JSON物件,再根據屬性名稱讀取資料:
string result = (string)jitem["Result"];
(要注意的是jitem["屬性名稱"]得到的會是JToken型態變數,
不加上(string)、(int)、(bool)轉型的話會出錯)
這樣子JSON解讀就大功告成了。
(注意一下,如果你在Windows 8/8.1上用Windows.Data.Json的話
在取得JSON物件的部分不知為何不能用Foreach,
非得用JSONArray.GetObjectAt(uint i)的方式才能取得JSON物件,
這種情況下真的不能用Foreach了,請注意)
-------------------------------------------
相對於JSON要裝外部函式庫而且使用上也不太直覺,
XML反而是寫起來麻煩解讀起來比較容易(用對函式庫的情況下)的類型
.NET一共提供了兩種類型的函式庫,
一種類型是System.Xml裡面附的XmlReader,
一種類型是System.Xml.Linq裡面附的XDocument
兩者都可以用來讀取XML,差別在於讀取方式:
XmlReader是從頭開始一行一行讀取的類型,因此讀取的流程需要小心控制,
不然就會產生想要讀取的資料讀不到,一直跳到別的地方那種難解的錯誤。
XDocument則是相對的把整個XML先讀完塞進記憶體後,
然後依照使用者的需要抽出需要的內容給使用者,因此使用上比較簡便
由於XDocument可以搭配Linq使用,
所以我這邊會以XDocument來解說如何讀取XML檔案,
不過各位也該注意的是,畢竟是把整個XML判讀完畢塞到記憶體後再抽出需要的內容
可想而知對記憶體的要求也就非常大,
1~2KB這種小檔案還好,一旦XML檔案過大,耗用的記憶體就會非常可觀
甚至一不小心就有可能因為衝破記憶體上限而在審查這關慘遭滑鐵盧(?
續前面的獲得資料部分,抓完資料後,
要產生XDocument也只需要下面這段宣告就可以:
XDocument xmlDoc = XDocument.Parse(content);
這樣就可以把抓到的XML內容轉換成XDocument變數
另外XDocument也有Load功能可以讀取本機的XML檔,
我還沒試過IsolateStorage行不行,
但是安裝資料夾的XML檔可以透過相對路徑的方式讀取,
一樣會產生XDocument變數
出來之後,就可以開始使用XElement來讀取下面的標籤:
XElement xmlContent = xmlDoc.Element("根標籤");
這個動作一定要做,不做的話系統沒有那麼聰明,不會自動讀取根標籤,
就會造成你要找的標籤位置全部都不對而導致查詢結果掛零
之後再從xmlContent來透過
.Element("標籤")讀取標籤內容、
.Attribute("屬性")讀取屬性內容
但別忘了要在前面加上(string)來強迫轉型,否則一樣報錯
另外XDocument讀出來的資訊一律都是字串型態,
數值之類的請使用Parse幫忙,布林值等其他型態還請活用if/else與switch/case來判斷
這邊有個比較好用的是Descendants這個函式
他會傳回這個標籤下所有子標籤,
搭配foreach、switch(xmldescendant.Name.toString())就可以判斷子標籤的類型
另外變體之一的Descendants("標籤"),
是傳回呼叫此函式的標籤下所有該名稱的標籤子集合
(例如var a = xmlContent.Descendants("Windows");是代表說,
將所有xmlContent代表標籤底下的所有Windows標籤轉成一個集合塞給a變數,
之後就能用foreach來讀取這些標籤)
而這個Descendants本身就是個LINQ集合
所以LINQ所有指令都能用在上面(包括First()之類的都沒問題)
此外除了回傳集合的Descendants、回傳標籤名稱的Name之類的後面不能再加以外,
Element、Attribute、Descendants都可以不斷連起來
例如ImageUrlIntro = (string)a.Element("Image").Element("Intro")之類的表現,
在XDocument裡面也是可以做到的。
活用XML最好的地方,主要就是讀取RSS了
因為RSS本身就是一種XML格式,只要知道格式的編寫,要做多少個RSS閱讀器都沒問題!
-----------------------------------------------------
http://sdrv.ms/1b5bqva
上面這個是自己寫的一個超簡單RSS閱讀器類別
(適用Windows Phone,Win8也幾乎不用改)
運用的技術就是這次提到的連接網路與讀取XML技術
想研究的話裡面本來就沒加密(是.cs檔)
想使用的話,引用WDFunc namespace後
用await RSSRead.GetRSSChannelsAsync()可以讀取一批RSS頻道
如果像不少的RSS檔只有一個Channel
用await RSSRead.GetRSSChannelAsync()就可以讀取那唯一一個RSS頻道
而RSS的內容是放在RSSChannel底下的ListItem這個List中
可以依照自己需求做增加修改
另外因為使用了這次提到的網路函式庫,所以要先裝那個網路函式庫才開得起來
不然應該會看到很多紅波浪錯誤。
這次的教學文章就先寫到這了
--
推 galilei503:原PO國文老師經長請假#1Duc8INo (StupidClown) 05/30 02:16
→ leo8064047:樓上的國文老師也...05/30 02:58
推 galilei503: 常...我不該採在地板上,我對不起地球..05/30 03:00
推 leo8064047: 踩05/30 03:15
推 galilei503:樓上你...想害我被做成簽名檔= =(沒有錯字了我撿查過!)05/30 04:56
推 leo8064047: 檢05/30 09:39
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 111.250.44.64
推 felaray:辛苦了 寫文章常常覺得比實作還累XD 02/06 23:52
總覺得要怎麼寫的妙筆生輝是最苦惱的問題(望
推 Impostable:隔行如隔山啊!我很認真的把它看完,但…佩服。 02/06 23:58
→ Impostable:雖然看不懂,但還是感謝原po的分享。 02/06 23:59
其實我是國文系的喔(咦
不過真的太深奧甚至數學滿天飛的那種我也真的會暈倒就是了(倒
※ 編輯: hoyunxian 來自: 111.250.44.64 (02/07 00:03)
→ hungys:為什麼不用JSON.NET的JsonConvert.Deserialize的泛型方法去 02/07 00:48
→ hungys:解析?一行搞定,用foreach也沒你說的問題 02/07 00:48
因為不見得抓到的JSON馬上就是我需要用的格式啊。
比方說像我上面舉的環保署例子,所有的數字都是字串格式不說
甚至還有「.05」這種連數字都不知道算不算(把0給省掉了)的數字
另外像他的風向是用方位角,也不是能直接用的數值
(沒找過資料的人應該不容易知道吧,現在童軍課幾乎都沒了......)
基本上我覺得這樣可自訂性比較高一些。
foreach那個部分我說明改正一下
會出問題的是Windows.Data.Json的JSONArray,
用Foreach反而抓不到JSON物件
推 PhreniaJebs:感謝開發者們。 02/07 00:52
推 felaray:我也是用json.net來解~不過當時初入json 搞蠻久才懂orz 02/07 01:28
我是先從XML進來,然後開始接觸Windows.Data.Json
再來才是JSON.NET
※ 編輯: hoyunxian 來自: 111.250.44.64 (02/07 01:40)
推 mhliu8:用心 推 02/07 01:35
推 superwave:我也習慣用JsonConvert.Deserialize的方法 02/07 09:51
→ superwave:只要內建好相對應的資料class就可以直接parse過去 02/07 09:51
→ superwave:適於格式太刁鑽的...我會先用全string的去解析 然後 02/07 09:52
→ superwave:再建新的資料型態parse過去 02/07 09:53
→ superwave:命名上就會用xxxModel 跟 xxxDisplayModel 區分 02/07 09:54
→ superwave:另外再推一下 原po超用心的!! 02/07 09:54
推 felaray:我是從wcf跳json 最近又為了需要把json轉rss 整個無言XDD 02/07 10:49
→ LiaoKen02:版上好像很多高手 連版主們都是XDDDDD 02/07 13:18
推 mike7689:為了職場技能,原本已經有C/C++的基礎(但物件觀念比較弱) 02/07 13:49
→ mike7689:想自修JAVA和C#(二選一)...原本比較prefer java...但 02/07 13:50
→ mike7689:現在看起來C#的應用也不少...連PSV/PS4的開發工具都用C# 02/07 14:48
→ mike7689:開始動搖了...@@ 02/07 14:48
→ fireslayer:C#比較好寫(因為VS比較好用) 02/07 20:14
→ hungys:其實也不一定要DisplayModel,就令一個新的property就然後在 02/07 21:43
→ hungys:get裡轉型就好了~ 02/07 21:43
推 hdtp:好文章! 03/18 23:27