Slee
Slee

Reputation: 28248

parse google maps geocode json response to object using Json.Net

I have a DB full of addresses I need to get lat and long for, so I want to loop through them and use Google Geocode to update my database. I am stuck as to how to parse the JSOn result to get what I need:

var address = "http://maps.google.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false";
var result = new System.Net.WebClient().DownloadString(address);
GoogleGeoCodeResponse test = JsonConvert.DeserializeObject<GoogleGeoCodeResponse>(result);

I thought I could simply build a quick class and use JSON.Net to deserialize the result, and it is kind of working but I think I am blowing it on my class structure:

public  class GoogleGeoCodeResponse {

    public string status { get; set; }
    public geometry geometry { get; set; }

}

public class geometry {
    public string location_type { get; set; }
    public location location { get; set; }
}

public class location {
    public string lat {get;set;}
    public string lng {get;set;}
}

Here is a sample of what get's returned from Google:

{
  "status": "OK",
  "results": [ {
    "types": [ "street_address" ],
    "formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
    "address_components": [ {
      "long_name": "1600",
      "short_name": "1600",
      "types": [ "street_number" ]
    }, {
      "long_name": "Amphitheatre Pkwy",
      "short_name": "Amphitheatre Pkwy",
      "types": [ "route" ]
    }, {
      "long_name": "Mountain View",
      "short_name": "Mountain View",
      "types": [ "locality", "political" ]
    }, {
      "long_name": "California",
      "short_name": "CA",
      "types": [ "administrative_area_level_1", "political" ]
    }, {
      "long_name": "United States",
      "short_name": "US",
      "types": [ "country", "political" ]
    }, {
      "long_name": "94043",
      "short_name": "94043",
      "types": [ "postal_code" ]
    } ],
    "geometry": {
      "location": {
        "lat": 37.4219720,
        "lng": -122.0841430
      },
      "location_type": "ROOFTOP",
      "viewport": {
        "southwest": {
          "lat": 37.4188244,
          "lng": -122.0872906
        },
        "northeast": {
          "lat": 37.4251196,
          "lng": -122.0809954
        }
      }
    }
  } ]
}

I am missing simple here I know it, anyone?

Upvotes: 20

Views: 33816

Answers (7)

Mush
Mush

Reputation: 11

Here is a C# implementation based on previous answers (with nullable enabled and JsonPropertyName attributes)

using System.Text.Json.Serialization;

namespace YourNameSpace;

public class GoogleGeoCodeResponse
{
    [JsonPropertyName("results")]
    public Results[] Results { get; set; } = null!;

    [JsonPropertyName("status")]
    public string Status { get; set; } = null!;
}

public class Results
{
    [JsonPropertyName("address_components")]
    public AddressComponent[] AddressComponents { get; set; } = null!;

    [JsonPropertyName("formatted_address")]
    public string FormattedAddress { get; set; } = null!;

    [JsonPropertyName("geometry")]
    public Geometry Geometry { get; set; } = null!;

    [JsonPropertyName("types")]
    public string[] Types { get; set; } = null!;
}

public class AddressComponent
{
    [JsonPropertyName("long_name")]
    public string LongName { get; set; } = null!;

    [JsonPropertyName("short_name")]
    public string ShortName { get; set; } = null!;

    [JsonPropertyName("types")]
    public string[] Types { get; set; } = null!;
}

public class Geometry
{
    [JsonPropertyName("bounds")]
    public Bounds Bounds { get; set; } = null!;

    [JsonPropertyName("location")]
    public Location Location { get; set; } = null!;

    [JsonPropertyName("location_type")]
    public string LocationType { get; set; } = null!;

    [JsonPropertyName("viewport")]
    public Viewport Viewport { get; set; } = null!;
}

public class Location
{
    [JsonPropertyName("lat")]
    public double Latitude { get; set; }

    [JsonPropertyName("lng")]
    public double Longitude { get; set; }
}

public class Viewport
{
    [JsonPropertyName("northeast")]
    public NorthEast NorthEast { get; set; } = null!;

    [JsonPropertyName("southwest")]
    public SouthWest SouthWest { get; set; } = null!;
}

public class Bounds
{
    [JsonPropertyName("northeast")]
    public NorthEast NorthEast { get; set; } = null!;
}

public class NorthEast
{
    [JsonPropertyName("lat")]
    public double Latitude { get; set; }

    [JsonPropertyName("lng")]
    public double Longitude { get; set; }
}

public class SouthWest
{
    [JsonPropertyName("lat")]
    public double Latitude { get; set; }

    [JsonPropertyName("lng")]
    public double Longitude { get; set; }
}

After that, just use the following to deserialize

JsonSerializer.Deserialize<GoogleGeoCodeResponse>(response.RawJson);

Upvotes: 0

Lee Templeton
Lee Templeton

Reputation: 11

Just for an update to this with a much easier method of handling what is wanted, all you need to do is the use the following:

var result = new System.Net.WebClient().DownloadString( <<ENTER ADDRESS URL HERE>> );
dynamic geo = JsonConvert.DeserializeObject(result);

then you can access the latitude with: geo.results[0].geometry.location.lat

Upvotes: 1

user7751256
user7751256

Reputation:

Make sure the class is Serializable, allow nullables

[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = true)]
public class GeocodeResponse
{
    public GeocodeResponse()
    {
      // can be empty or you can initiate the properties here
    }

    [XmlElement("location ")]
    [Display(Name = "location ")]
    // add json attributes as well
    public location  location { get; set; }

    public string status { get; set; }
  }

Upvotes: 0

planetdonovan
planetdonovan

Reputation: 21

Thanks to JEuvin above, I was able to easily switch from XML to Json with a few mods to the code above (specifically changing lat and lng to decimal or double) and also had to change address_components.types to string[] to get it to work for me. I then refactored a bit so that the same classes can be deserialized from XML or Json interchangeably.

Maybe this will help someone too...

using System;
using System.Xml.Serialization;

[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class GeocodeResponse
{
    public GeocodeResponse()
    {
    }

    [XmlElement("result")]

    public results[] results { get; set; }

    public string status { get; set; }
}

[XmlType(AnonymousType = true)]
public class results
{
    public results()
    {
    }

    [XmlElement("address_component")]

    public address_component[] address_components { get; set; }

    public string formatted_address { get; set; }

    public geometry geometry { get; set; }

    [XmlElement("type")]
    public string[] types { get; set; }

    public string[] postcode_localities { get; set; }

    public bool partial_match { get; set; }

    public string place_id { get; set; }
}

[XmlType(AnonymousType = true)]
public class address_component
{
    public address_component()
    {
    }

    public string long_name { get; set; }

    public string short_name { get; set; }

    [XmlElement("type")]
    public string[] types { get; set; }
}

[XmlType(AnonymousType = true)]
public class geometry
{
    public geometry()
    {
    }

    public bounds bounds { get; set; }

    public location location { get; set; }

    public string location_type { get; set; }

    public viewport viewport { get; set; }
}

[XmlType(AnonymousType = true)]
public class location
{
    public location()
    {
    }

    public double lat { get; set; }

    public double lng { get; set; }
}

[XmlType(AnonymousType = true)]
public class viewport
{
    public viewport()
    {
    }

    public northeast northeast { get; set; }

    public southwest southwest { get; set; }
}

[XmlType(AnonymousType = true)]
public class bounds
{
    public bounds()
    {
    }

    public northeast northeast { get; set; }
}

[XmlType(AnonymousType = true)]
public class northeast
{
    public northeast()
    {
    }

    public double lat { get; set; }

    public double lng { get; set; }
}

[XmlType(AnonymousType = true)]
public class southwest
{
    public southwest()
    {
    }

    public double lat { get; set; }

    public double lng { get; set; }
}

(edited with addition of postcode_localities and partial_match properties)

Upvotes: 2

JEuvin
JEuvin

Reputation: 1039

C# Object Code I added a few extra classes, not sure if they are new to the API but I thought this might be helpful to someone.

public class GoogleGeoCodeResponse
    {
        public results[] results { get; set; }
        public string status { get; set; }

    }

    public class results
    {
        public address_component[] address_components { get; set; }
        public string formatted_address { get; set; }
        public geometry geometry { get; set; }
        public string[] types { get; set; }
    }

    public class address_component
    {
        String long_name { get; set; }
        String short_name { get; set; }
        String types { get; set; }

    }

    public class geometry
    {
        public bounds bounds { get; set; }
        public location location { get; set; }
        public string location_type { get; set; }
        public viewport viewport { get; set; }
    }

    public class location
    {
        public string lat { get; set; }
        public string lng { get; set; }
    }

    public class viewport
    {
        public northeast northeast { get; set; }
        public southwest southwest { get; set; }
    }

    public class bounds
    {
        public northeast northeast { get; set; }
    }

    public class northeast
    {
        public string lat { get; set; }
        public string lng { get; set; }
    }

    public class southwest
    {
        public string lat { get; set; }
        public string lng { get; set; }
    }

Upvotes: 3

matt.j.crawford
matt.j.crawford

Reputation: 392

You can use a dynamic object rather than defining the object.

 public static dynamic GEOCodeAddress(String Address)
    {
        var address = String.Format("http://maps.google.com/maps/api/geocode/json?address={0}&sensor=false", Address.Replace(" ", "+"));
        var result = new System.Net.WebClient().DownloadString(address);
        JavaScriptSerializer jss = new JavaScriptSerializer();
        return jss.Deserialize<dynamic>(result);
    }

Upvotes: 20

Antonio
Antonio

Reputation: 526

I tried this, made a simple test and it worked (added results and other):

public class GoogleGeoCodeResponse
{

    public string status { get; set; }
    public results[] results { get; set; }

}

public class results
{
    public string formatted_address { get; set; }
    public geometry geometry { get; set; }
    public string[] types { get; set; }
    public address_component[] address_components { get; set; }
}

public class geometry
{
    public string location_type { get; set; }
    public location location { get; set; }
}

public class location
{
    public string lat { get; set; }
    public string lng { get; set; }
}

public class address_component
{
    public string long_name { get; set; }
    public string short_name { get; set; }
    public string[] types { get; set; }
}

Upvotes: 51

Related Questions