0

I have the following class:

public class Location
{
    public string Name { get; set; }
    public long Latitude { get; set; }
    public long Longitude { get; set; }
    public string AddressLine { get; set; }
    public string FormattedAddress { get; set; }
    public string PostalCode { get; set; }


}

And the following XML response from my RESTful request:

<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/search/local/ws/rest/v1">
<Copyright>Copyright © 2011 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.</Copyright>
<BrandLogoUri>http://dev.virtualearth.net/Branding/logo_powered_by.png</BrandLogoUri>
<StatusCode>200</StatusCode>
<StatusDescription>OK</StatusDescription>
<AuthenticationResultCode>ValidCredentials</AuthenticationResultCode>
<TraceId>xxx</TraceId>
<ResourceSets>
<ResourceSet>
  <EstimatedTotal>1</EstimatedTotal>
  <Resources>
    <Location>
      <Name>L4 0TH, Liverpool, Liverpool, United Kingdom</Name>
      <Point>
        <Latitude>53.431259840726852</Latitude>
        <Longitude>-2.9616093635559082</Longitude>
      </Point>
      <BoundingBox>
        <SouthLatitude>53.427397123156176</SouthLatitude>
        <WestLongitude>-2.9702530969854752</WestLongitude>
        <NorthLatitude>53.435122558297529</NorthLatitude>
        <EastLongitude>-2.9529656301263412</EastLongitude>
      </BoundingBox>
      <EntityType>Postcode1</EntityType>
      <Address>
        <AdminDistrict>England</AdminDistrict>
        <AdminDistrict2>Liverpool</AdminDistrict2>
        <CountryRegion>United Kingdom</CountryRegion>
        <FormattedAddress>L4 0TH, Liverpool, Liverpool, United Kingdom</FormattedAddress>
        <Locality>Liverpool</Locality>
        <PostalCode>L4 0TH</PostalCode>
      </Address>
      <Confidence>High</Confidence>
    </Location>
  </Resources>
</ResourceSet>

How can I get the value of Name, Latitude, Longitude, AddressLine, FormattedAddress and PostalCode into my properties?

My method is:

internal Location ListLocations()
    {
        Location loc = new Location();
        string query = "L40TH";
        string key = "MyBingMapsKey";
        string url = string.Format("http://dev.virtualearth.net/REST/v1/Locations/{0}?o=xml&key={1}", query, key);
        XElement elements = GetResponse(url);

        // stuck here!

    }
Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Brett
  • 1,923
  • 3
  • 18
  • 24
  • What exactly should go in `AddressLine`? Is it the concatenated values of all the elements in the Address element? – daveaglick Jul 06 '11 at 16:22
  • Also note that in your `Location` class you've got the `Latitude` and `Longitude` as integer values, but they're coming in as floating point (svick alluded to this in his solution). – daveaglick Jul 06 '11 at 16:58
  • @somedave, I was assuming that they could store lat. and long. as total number of seconds or something like that. – svick Jul 06 '11 at 17:09
  • @somedave Some of the XML nodes return appear based on the query passed. AddressLine doesn't appear when a postcode is passed but does when an address is passed. – Brett Jul 07 '11 at 10:37

2 Answers2

4

I would do it like this:

static readonly XNamespace Ns = "http://schemas.microsoft.com/search/local/ws/rest/v1";

static Location LocationFromXml(XElement element)
{
    var point = element.Element(Ns + "Point");
    return new Location
    {
        Name = (string)element.Element(Ns + "Name"),
        Latitude = (long)(float)point.Element(Ns + "Latitude"), // probably not exactly what you want
        Longitude = (long)(float)point.Element(Ns + "Longitude"),
        AddressLine = null, // not sure what do you want here
        FormattedAddress = null, // ditto
        PostalCode = (string)element.Element(Ns + "Address").Element(Ns + "PostalCode")
    };
}

And then in ListLocations():

var location = elements.Element(Ns + "ResourceSets")
                       .Element(Ns + "ResourceSet")
                       .Element(Ns + "Resources")
                       .Element(Ns + "Location");
return LocationFromXml(location);
svick
  • 236,525
  • 50
  • 385
  • 514
  • I really like this answer as an alternative to XPath (probably more efficient too since it doesn't have to use the XPath parser/engine). – daveaglick Jul 06 '11 at 16:57
  • @svick Thanks for that. Seems obvious now but I guess it always does. – Brett Jul 07 '11 at 10:37
0

You can probably use XPath to easily get to the right data and manually fill in the Location properties (or even better, add the code to the Location class). The key is the XPath extension methods for Linq to XML. Particularly look at XPathSelectElement and XPathEvaluate:

loc.Name = elements.XPathSelectElement("//Name").Value;
loc.Latitude = Convert.ToInt64(elements.XPathSelectElement("//Latitude").Value);
loc.Longitude = Convert.ToInt64(elements.XPathSelectElement("//Longitude").Value);
//loc.AddressLine = ??? (Not sure what the intended value is here...)
loc.FormattedAddress = elements.XPathSelectElement("//FormattedAddress").Value;
loc.PostalCode = elements.XPathSelectElement("//PostalCode").Value;
daveaglick
  • 3,600
  • 31
  • 45
  • From the structure of the XML, it it seems there may be more than one response. – svick Jul 06 '11 at 16:34
  • The `XPathSelectElement` extension method will always return the first `XElement` the XPath expression finds. In this case, all the properties of the `Location` object will get set to values in the subelements of the first `` result. If more than one result is provided and we want `Location` objects for each OR we want to set the single `Location` object to values other than the first `` result element, then more sophisticated logic is required (though I took from the question that we're just looking for the first since it wasn't stated otherwise). – daveaglick Jul 06 '11 at 16:46
  • 1
    Also note that the answer above does not take namespaces into account. Given that the result XML may contain namespaces, you might have to use an `IXmlNamespaceResolver` to get the XPath methods to work. [See this blog post](http://dannythorpe.com/2010/11/12/using-namespaces-with-linq-xpathselectelement/). – daveaglick Jul 06 '11 at 16:50