我正在使用下面的代码来获取给定纬度和经度的城市名称。
但是当此行运行时,代码停止:
var responseElement = XElement.Parse(response);
它停止响应,并且不会引发任何异常。
我猜这可能是异步调用的问题。
任何人都可以帮助我解决这个问题,或者建议使用 iOS SDK 的类似代码吗?谢谢
private async Task<string> ReturnCity(string lat, string lon)
{
string city = "None";
string baseUri = string.Format("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", lat, lon);
HttpClient client = new HttpClient();
var response = await client.GetStringAsync(baseUri);
var responseElement = XElement.Parse(response);
IEnumerable<XElement>statusElement = from st in responseElement.Elements("status") select st;
if (statusElement.FirstOrDefault() != null)
{
string status = statusElement.FirstOrDefault().Value;
if (status.ToLower() == "ok")
{
IEnumerable<XElement> resultElement = from rs in responseElement.Elements("result") select rs;
if (resultElement.FirstOrDefault() != null)
{
IEnumerable<XElement> addressElement = from ad in resultElement.FirstOrDefault().Elements("address_component") select ad;
foreach (XElement element in addressElement)
{
IEnumerable<XElement> typeElement = from te in element.Elements("type") select te;
string type = typeElement.FirstOrDefault().Value;
if(type=="locality")
{
IEnumerable<XElement> cityElement = from ln in element.Elements("long_name") select ln;
city = cityElement.FirstOrDefault().Value;
return city;
break;
}
}
}
}
}
return city;
}
我浏览了调试器,发现了响应的值。它看起来像一个有效的 XML。有什么想法吗?
<?xml version="1.0" encoding="UTF-8"?>
<GeocodeResponse>
<status>OK</status>
<result>
<type>airport</type>
<type>transit_station</type>
<type>establishment</type>
<formatted_address>Lisbon Portela Airport (LIS), Alameda das Comunidades Portuguesas, 1700-111 Lisboa, Portugal</formatted_address>
<address_component>
<long_name>Lisbon Portela Airport</long_name>
<short_name>Lisbon Portela Airport</short_name>
</address_component>
<address_component>
<long_name>Alameda das Comunidades Portuguesas</long_name>
<short_name>Alameda das Comunidades Portuguesas</short_name>
<type>route</type>
</address_component>
<address_component>
<long_name>Lisboa</long_name>
<short_name>Lisboa</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisboa</long_name>
<short_name>Lisboa</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<address_component>
<long_name>1700-111</long_name>
<short_name>1700-111</short_name>
<type>postal_code</type>
</address_component>
<geometry>
<location>
<lat>38.7755936</lat>
<lng>-9.1353667</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.7623900</lat>
<lng>-9.1475505</lng>
</southwest>
<northeast>
<lat>38.7994779</lat>
<lng>-9.1236185</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.7623900</lat>
<lng>-9.1475505</lng>
</southwest>
<northeast>
<lat>38.7994779</lat>
<lng>-9.1236185</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJgwHZFkYyGQ0RRm0DWD6lZgo</place_id>
</result>
<result>
<type>route</type>
<formatted_address>Lisbon Portela Airport (LIS), Rua E, 1700-111 Lisboa, Portugal</formatted_address>
<address_component>
<long_name>Rua E</long_name>
<short_name>R. E</short_name>
<type>route</type>
</address_component>
<address_component>
<long_name>Lisbon Portela Airport</long_name>
<short_name>Lisbon Portela Airport</short_name>
</address_component>
<address_component>
<long_name>Lisboa</long_name>
<short_name>Lisboa</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisboa</long_name>
<short_name>Lisboa</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<address_component>
<long_name>1700-111</long_name>
<short_name>1700-111</short_name>
<type>postal_code</type>
</address_component>
<address_component>
<long_name>1700</long_name>
<short_name>1700</short_name>
<type>postal_code_prefix</type>
<type>postal_code</type>
</address_component>
<geometry>
<location>
<lat>38.7757984</lat>
<lng>-9.1304833</lng>
</location>
<location_type>GEOMETRIC_CENTER</location_type>
<viewport>
<southwest>
<lat>38.7744765</lat>
<lng>-9.1317496</lng>
</southwest>
<northeast>
<lat>38.7771745</lat>
<lng>-9.1290516</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.7748799</lat>
<lng>-9.1307609</lng>
</southwest>
<northeast>
<lat>38.7767711</lat>
<lng>-9.1300403</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJjdzMckIyGQ0RvIXYZCCI82k</place_id>
</result>
<result>
<type>locality</type>
<type>political</type>
<formatted_address>Lisbon, Portugal</formatted_address>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>38.7222524</lat>
<lng>-9.1393366</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.6913994</lat>
<lng>-9.2298356</lng>
</southwest>
<northeast>
<lat>38.7958538</lat>
<lng>-9.0905718</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.6913994</lat>
<lng>-9.2298356</lng>
</southwest>
<northeast>
<lat>38.7958538</lat>
<lng>-9.0905718</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJO_PkYRozGQ0R0DaQ5L3rAAQ</place_id>
</result>
<result>
<type>postal_code</type>
<formatted_address>1700-111 Lisbon, Portugal</formatted_address>
<address_component>
<long_name>1700-111</long_name>
<short_name>1700-111</short_name>
<type>postal_code</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>locality</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Olivais</long_name>
<short_name>Olivais</short_name>
<type>administrative_area_level_3</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>38.7661892</lat>
<lng>-9.1291486</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.7544060</lat>
<lng>-9.1483947</lng>
</southwest>
<northeast>
<lat>38.7870843</lat>
<lng>-9.1239064</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.7544060</lat>
<lng>-9.1483947</lng>
</southwest>
<northeast>
<lat>38.7870843</lat>
<lng>-9.1239064</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJS-qk_0UyGQ0RN3v7SZnU9D8</place_id>
</result>
<result>
<type>postal_code_prefix</type>
<type>postal_code</type>
<formatted_address>1700, Portugal</formatted_address>
<address_component>
<long_name>1700</long_name>
<short_name>1700</short_name>
<type>postal_code_prefix</type>
<type>postal_code</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>38.7600325</lat>
<lng>-9.1400807</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.7448641</lat>
<lng>-9.1567550</lng>
</southwest>
<northeast>
<lat>38.7870843</lat>
<lng>-9.1239064</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.7448641</lat>
<lng>-9.1567550</lng>
</southwest>
<northeast>
<lat>38.7870843</lat>
<lng>-9.1239064</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJdVtq_1kyGQ0RYKU7DsHrABw</place_id>
</result>
<result>
<type>administrative_area_level_3</type>
<type>political</type>
<formatted_address>Olivais, Portugal</formatted_address>
<address_component>
<long_name>Olivais</long_name>
<short_name>Olivais</short_name>
<type>administrative_area_level_3</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>38.7721510</lat>
<lng>-9.1179465</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.7502229</lat>
<lng>-9.1483924</lng>
</southwest>
<northeast>
<lat>38.7870963</lat>
<lng>-9.0905718</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.7502229</lat>
<lng>-9.1483924</lng>
</southwest>
<northeast>
<lat>38.7870963</lat>
<lng>-9.0905718</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJccbEUz4yGQ0RsEKQ5L3rAAU</place_id>
</result>
<result>
<type>administrative_area_level_2</type>
<type>political</type>
<formatted_address>Lisbon, Portugal</formatted_address>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_2</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>38.7222986</lat>
<lng>-9.1393188</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.6913994</lat>
<lng>-9.2298356</lng>
</southwest>
<northeast>
<lat>38.7958538</lat>
<lng>-9.0905718</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.6913994</lat>
<lng>-9.2298356</lng>
</southwest>
<northeast>
<lat>38.7958538</lat>
<lng>-9.0905718</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJMabWPRAzGQ0RRFqNEqmj6AI</place_id>
</result>
<result>
<type>administrative_area_level_1</type>
<type>political</type>
<formatted_address>Lisbon, Portugal</formatted_address>
<address_component>
<long_name>Lisbon</long_name>
<short_name>Lisbon</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>38.7223263</lat>
<lng>-9.1392714</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>38.6731604</lat>
<lng>-9.5005266</lng>
</southwest>
<northeast>
<lat>39.3177286</lat>
<lng>-8.7819208</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>38.6731604</lat>
<lng>-9.5005266</lng>
</southwest>
<northeast>
<lat>39.3177286</lat>
<lng>-8.7819208</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJWxIr4ajVGA0RwCyQ5L3rAAM</place_id>
</result>
<result>
<type>country</type>
<type>political</type>
<formatted_address>Portugal</formatted_address>
<address_component>
<long_name>Portugal</long_name>
<short_name>PT</short_name>
<type>country</type>
<type>political</type>
</address_component>
<geometry>
<location>
<lat>39.3998720</lat>
<lng>-8.2244540</lng>
</location>
<location_type>APPROXIMATE</location_type>
<viewport>
<southwest>
<lat>36.9601772</lat>
<lng>-9.5171107</lng>
</southwest>
<northeast>
<lat>42.1542048</lat>
<lng>-6.1902091</lng>
</northeast>
</viewport>
<bounds>
<southwest>
<lat>32.4037400</lat>
<lng>-31.2752439</lng>
</southwest>
<northeast>
<lat>42.1542048</lat>
<lng>-6.1902091</lng>
</northeast>
</bounds>
</geometry>
<place_id>ChIJ1SZCvy0kMgsRQfBOHAlLuCo</place_id>
</result>
</GeocodeResponse>
我使用谷歌提供的相同反向地理服务实现了类似的东西,但 JSON 版本。根据我的经验,你不能假设你需要的任何数据,例如城市,都会在那里。此外,您可能需要检查零结果。看看下面我是如何实现它的:
public async Task<LocationAddressModel> GetLocationAddressAsync (LocationAddressRequest locationAddressRequest)
{
Task<IRestResponse> task = GetAddressForLocation (locationAddressRequest);
IRestResponse response = await task;
var locationAddress = new LocationAddressModel ();
if (response != null) {
RootObject locationAddresses = JsonConvert.DeserializeObject<RootObject> (response.Content);
if (locationAddresses.status.Equals (Constants.ZERO_RESULTS)) {
// Zero results for that location, setting location to Unknown.
locationAddress.FormattedAddress = "UnknownLocation".Local();
locationAddress.City = "CityNotFound".Local ();
locationAddress.County = "CountyNotFound".Local ();
locationAddress.FirstLineOfAddress = "AddressNotFound".Local ();
locationAddress.Postcode = "PostcodeNotFound".Local ();
} else {
try {
Result routeAddress = locationAddresses.results.FirstOrDefault (x => x.types.Contains (Constants.ROUTE));
if (routeAddress != null)
{
locationAddress.FormattedAddress = routeAddress.formatted_address;
var postcode = routeAddress.address_components.FirstOrDefault(x => x.types.Contains (Constants.POSTCODE));
locationAddress.Postcode = postcode != null ? postcode.long_name : "PostcodeNotFound".Local ();
var firstLineOfAddress = routeAddress.address_components.FirstOrDefault(x => x.types.Contains (Constants.ROUTE));
locationAddress.FirstLineOfAddress = firstLineOfAddress != null ? firstLineOfAddress.long_name : "AddressNotFound".Local ();
var city = routeAddress.address_components.FirstOrDefault(x => x.types.Contains (Constants.CITY));
locationAddress.City = city != null ? city.long_name : "CityNotFound".Local ();
}
else
{
// If the location doesnt have a route address just return the first result formatted address
locationAddress.FormattedAddress = locationAddresses.results.FirstOrDefault ().formatted_address;
}
// Remove any numbers at the start, to save users from knowing how inaccurate GPS can be.
locationAddress.FormattedAddress = Regex.Replace (locationAddress.FormattedAddress, "^\d+\s", string.Empty);
}
catch (Exception e)
{
Debug.WriteLine ("Exception in reverse geolocation data");
// If we get some crazy data also set it to unknown
locationAddress.FormattedAddress = "UnknownLocation".Local();
}
}
}
return locationAddress;
}
private async Task<IRestResponse> GetAddressForLocation (LocationAddressRequest locationAddressRequest) {
IRestRequest restRequest = _restSharpGoogleMapsSingletonBase.Factory.Create(Constants.GET_LOCATION_ADDRESS, Method.GET);
restRequest.AddUrlSegment ("lat", locationAddressRequest.Lat);
restRequest.AddUrlSegment ("lng", locationAddressRequest.Lng);
try
{
var result = await _helper.ExecuteTaskAsync(restRequest);
if (result.StatusCode == (int)HttpStatusCode.OK)
{
Debug.WriteLine("Rest Request Succeeded in Google Maps GeoCode API");
return result;
}
else
{
Debug.WriteLine("Rest Request Failed in Google Maps GeoCode API: Wrong status code received");
return null;
}
}
catch(WebException webException)
{
// Windows Store application profile only supports a limited set of WebExceptionStatus.
// So the PCL can only support that set, Check for the Timeout here.
if(webException.Status == (WebExceptionStatus)14)
{
Debug.WriteLine("Timed out in Google Maps GeoCode API");
}
return null;
}
catch (Exception exception)
{
return null;
}
}
我正在使用的常量:
namespace GoogleMaps
{
public static class Constants
{
public static string GOOGLEMAPSURL = "http://maps.googleapis.com/";
public static string GET_LOCATION_ADDRESS = "/maps/api/geocode/json?latlng={lat},{lng}";
public static string ROUTE = "route";
public static string FORMATTED_ADDRESS = "formatted_address";
public static string POSTCODE = "postal_code";
public static string CITY = "locality";
public static string ZERO_RESULTS = "ZERO_RESULTS";
}
}
希望这有帮助。
问题发生在
string type = typeElement.FirstOrDefault ().Value;
所以我必须测试是否 typeElement.FirstOrDefault () != null
如下:
private async Task<string> ReturnCity(string lat, string lon)
{
string city = "None";
string baseUri = string.Format ("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", lat, lon);
HttpClient client = new HttpClient ();
string response = await client.GetStringAsync (baseUri);
XElement responseElement = XElement.Parse (response);
IEnumerable<XElement> statusElement = from st in responseElement.Elements ("status")
select st;
if (statusElement.FirstOrDefault () != null) {
string status = statusElement.FirstOrDefault ().Value;
if (status.ToLower () == "ok") {
IEnumerable<XElement> resultElement = from rs in responseElement.Elements ("result")
select rs;
if (resultElement.FirstOrDefault () != null) {
IEnumerable<XElement> addressElement = from ad in resultElement.FirstOrDefault ().Elements ("address_component")
select ad;
foreach (XElement element in addressElement) {
IEnumerable<XElement> typeElement = from te in element.Elements ("type")
select te;
if (typeElement.FirstOrDefault () != null) {
string type = typeElement.FirstOrDefault ().Value;
if (type == "locality") {
IEnumerable<XElement> cityElement = from ln in element.Elements ("long_name")
select ln;
city = cityElement.FirstOrDefault ().Value;
return city;
}
}
}
}
}
}
return city;
}