Windows Phone 7 - 使用Google Map API將地址轉成座標
最近在撰寫一個使用Bing Map來操作的App,遇到要提供用戶可以輸入自己的地址,並且地址轉成座標後,
自動標示於地圖上。其實這功能在撰寫Android App裡我已經有遇過了,剛好最近在撰寫WP7,又拿出來簡
單的做個筆記。
Google Map API提供開發人員可以將輸入的地址轉成對應的座標,可以在<Google Geocoding API >參考得到。
然而,該篇將介紹在WP7中如何取得資料的方式。
由於Google提供「http://maps.googleapis.com/maps/api/geocode/output?parameters」該網址段,透過參數的方式,
只需在特定的Query String key加上要搜尋的地址與要回傳的格式內容,即可以完成我們需要的功能。至於詳細參數的使
用方式,我透過擷取<Google Geocoding API>的內容,如下:
參數 | 類型 | 說明 |
output | json | (建議使用) 表示輸出格式為 JavaScript 物件註釋 (JSON); |
xml | 表示輸出格式為 XML,相對資料大小比json大很多; | |
parameters | address | (必要):您要進行地理編碼的地址。address與latlng,擇一使用。 |
latlng |
(必要):您將為此文字經/緯度值取得最接近的人類可讀地址。 address與latlng,擇一使用。 |
|
bounds | (選用):您可在此檢視區的邊框中,進一步自訂調整地理編碼結果。(如需詳細資訊,請參閱下方的「檢視區自訂調整」)。 | |
region | (選用):將區域代碼指定為 ccTLD (「頂層網域」) 的兩位字元值。(如需詳細資訊,請參閱下方的「區域自訂調整」)。 | |
language | (選用):結果傳回時使用的語言。請參閱「支援的網域語言清單」。 | |
sensor |
(必要):指出地理編碼要求的來源裝置是否附有位置感應器。這個值必須是 true 或 false 。 |
重要用的參數是:address與sensor,所以往下就來看看回傳的結果,並說明要建立成.NET可以讀取的序列化類別為何。
a. 使用URL取得JSON回傳結果:
使用Google Geocoding API方式,只需在指定的網址內加上需要的key & value,如下:
回傳的結果,我們透過<http://jsonviewer.stack.hu/>的結果來加以分析:
透過上圖可以看到,有很多集合的部分,這些集合的部分要轉成資料類別時,這些集合就是一個Collection的屬性,
例如:result、address_components、geometry、types屬性。那單一值就是透過string類型來加以儲存,例如:
status、location_type、formatted_address、lat、lng、long_name、short_name。
從上圖也可以看出,Geocoding API提供的轉換後的完整資訊,當然,如果今天隨便輸入地址的話,回傳的結果就
不一樣了,相關的錯誤訊息,也可以直接參數Google Geocoding API上的說明。如果今天需要是找附近資訊的話,
就需要用另一個Google Places API 了。
〉轉成至WP7的寫法:
撰寫WP7處理JSON的內容,在很多文章都提過,與WP7相關的文章,可以參考下述連結的作法:
<[WP7] 使用 JSON 方式來處理 台北市公開政府資料平臺(ODGI) 資料 ─ 以旅館業範例>,由於該篇的作業非常清楚,
這裡我就不再重覆說明相關的作法,只針對如何定義接收Google Geocoding API回傳結果的資料類別,以下直接撰
寫程式來說明如何定義。
a. 先定義要儲存的資料實體:
1: using System;
2: using System.Runtime.Serialization;
3: using System.Collections.Generic;
4:
5: namespace Location.Data
6: {
7: /// <summary>
8: /// Google Map API, Address convert to Location, Data Entity. by Json format.
9: /// </summary>
10: [DataContract]
11: public class GAddressGeoCollection
12: {
13: public GAddressGeoCollection() { }
14: /// <summary>
15: /// JSON回傳的results集合。
16: /// </summary>
17: [DataMember]
18: public List<GAddressGeoResult> results { get; set; }
19: /// <summary>
20: /// JSON回傳的status字串。
21: /// </summary>
22: [DataMember]
23: public string status { get; set; }
24: }
25:
26: /// <summary>
27: /// results資料結構。
28: /// </summary>
29: [DataContract]
30: public class GAddressGeoResult
31: {
32: public GAddressGeoResult() { }
33: //[DataMember]
34: //public List<GAddressComponent> address_components { get; set; }
35: [DataMember]
36: public string formatted_address { get; set; }
37: /// <summary>
38: /// 座標資料集合。
39: /// </summary>
40: [DataMember]
41: public GAddressGeoEntity geometry { get; set; }
42: }
43:
44: [DataContract]
45: public class GAddressComponent
46: {
47: public GAddressComponent() { }
48: [DataMember]
49: public string long_name { get; set; }
50: [DataMember]
51: public string short_name { get; set; }
52: //[DataMember]
53: //public string types { get; set; }
54: }
55:
56: [DataContract]
57: public class GAddressGeoEntity
58: {
59: public GAddressGeoEntity() { }
60: [DataMember]
61: public GAddressLocation location { get; set; }
62: [DataMember]
63: public string location_type { get; set; }
64: }
65:
66: [DataContract]
67: public class GAddressLocation
68: {
69: public GAddressLocation() { }
70: [DataMember]
71: public string lat { get; set; }
72: [DataMember]
73: public string lng { get; set; }
74: }
75: }
上述主要定義了接收Google Geocoding API的資料類別,該類別由的「屬性名稱」要與JSON回傳結果中元素名稱一致,
才能對應起來,例如:results、status。然而,results是一個集合,所以另外定義了GAddressGeoResult的類別來接收
results的結果,以這個概念往下去推演,results中也有很多集合,這些集合的item也需要一個獨立的資料類別來定義,
如此一來,整個資料實體就能完成對應起來了。
b. 實作要呼叫Google Geocoding API的Handler:
[注意] 要使用的參考包括:
System.Runtime.Serialization; System.ServiceModel; System.Servicemodel.Web;
1: public class GoogleSearchHandler
2: {
3: private string gSearchURL = "http://maps.googleapis.com/maps/api/geocode/json?address={0}&sensor=true";
4:
5: /// <summary>
6: /// 搜尋地址,並轉換成座標。
7: /// </summary>
8: /// <param name="pAddress"></param>
9: public void SearchAddress(string pAddress)
10: {
11: if (DeviceNetworkInformation.IsWiFiEnabled || DeviceNetworkInformation.IsCellularDataEnabled
12: || DeviceNetworkInformation.IsNetworkAvailable)
13: {
14: try
15: {
16: gSearchURL = string.Format(gSearchURL, pAddress);
17: WebClient tWebClient = new WebClient();
18: tWebClient.DownloadStringCompleted +=
19: new DownloadStringCompletedEventHandler(tWebClient_DownloadStringCompleted);
20: tWebClient.DownloadStringAsync(
21: new Uri(gSearchURL));
22: }
23: catch (Exception)
24: {
25: throw;
26: }
27: }
28: }
29:
30: /// <summary>
31: /// 取得指定URL回傳的結果,觸發事件。
32: /// </summary>
33: /// <param name="sender"></param>
34: /// <param name="e"></param>
35: void tWebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
36: {
37: GAddressGeoCollection tCollection = null;
38: Exception tException = null;
39: if (e.Error == null)
40: {
41: try
42: {
43: tCollection = new GAddressGeoCollection();
44: DataContractJsonSerializer tJsonSerial = new DataContractJsonSerializer(typeof(GAddressGeoCollection));
45: MemoryStream tMS = new MemoryStream(Encoding.UTF8.GetBytes(e.Result));
46: tCollection = tJsonSerial.ReadObject(tMS) as GAddressGeoCollection;
47: //判斷搜尋結果不為Null時,才是真正可以使用的資料
48: if (tCollection != null && tCollection.results != null)
49: {
50: Utility.GAddressGeoResult = tCollection.results[0];
51: }
52: }
53: catch (Exception ex)
54: {
55: tException = ex;
56: }
57: }
58: }
59: }
上述是範例程式主要透過WebClient呼叫DownloadStringAsync的事件來進行資料的下載後,再透過.NET內鍵的
DataContractJsonSerializer類別將資料加以序列化,配置成上述定義的資料類別。
[補充]
a. 如果今天希望透過座標找到附近相關的地方資訊的話,可以參考<Google Places API>,並且注意下方的參數使用方式:
參數 | 類型 | 說明 |
output | xml | (建議使用) 表示輸出格式為 JavaScript 物件註釋 (JSON) |
json | 表示輸出格式為 XML (傳輸量會較JSON大) | |
parameters | location |
(必要) 您要擷取「地方資訊」附近的經緯度值。這必須以 google.maps.LatLng 物件方式提供。 |
radius |
(必要) 「地方資訊」結果傳回的距離 (以公尺為單位)。建議的最佳作法是根據位置感應器提供的位置信號精確性,設定 radius 。請注意,設定 radius 會將結果自訂調整至所指示的區域,但不會將結果完全限制在指定的區域。 |
|
types |
(選用) 將結果限制為至少符合一個指定類型的「地方資訊」。類型應以直立線符號分隔 (type1|type2|etc )。請參閱「支援類型的清單」。 |
|
language | (選用) 指出應以何種語言傳回結果 (如有可能) 的語言代碼。請參閱「支援語言的清單」及其代碼。請注意,我們經常更新支援的語言,因此這份清單可能會有遺漏。 | |
name |
(選用) 用以比對地方資訊名稱的字詞。結果將會限制在包含所傳遞之 name 值的結果中。包含名稱時,所搜尋的區域可能會擴大,以確保會有適當數量的結果。 |
|
sensor |
(必要) 表示來自裝置的「地點」要求是否使用位置感應器 (如 GPS) 來判斷這項要求中所傳送的位置。這個值必須是 true 或 false 。 |
|
key | (必要) 您應用程式的 API 金鑰。此金鑰會識別您的應用程式,以進行配額管理,如此一來,從您的應用程式新增的「地方資訊」就可立即供您的應用程式使用。請造訪 API 控制台建立「API 專案」,並取得您的金鑰。 |
======
以上是簡單記錄撰寫的心得,由於LBS的盛行,這樣的功能是一定要學會的。這樣才能撰寫出相關在地圖上
加上更多豐富內容的App。撰寫的內容有點偷懶,請多包涵。
References:
‧[WP7] 使用 JSON 方式來處理 台北市公開政府資料平臺(ODGI) 資料 ─ 以旅館業範例
‧Google Places API (重要)
‧Google Distance Matrix API (重要)
‧Google Directions API (重要)
‧Google Geocoding API (重要)