I have the following Google geocoding XML
<GeocodeResponse>
<status>OK</status>
<result>
<type>street_address</type>
<formatted_address>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA</formatted_address>
<address_component>
<long_name>1600</long_name>
<short_name>1600</short_name>
<type>street_number</type>
</address_component>
<address_component>
<long_name>Amphitheatre Pkwy</long_name>
<short_name>Amphitheatre Pkwy</short_name>
<type>route</type>
</address_component>
....
<geometry>
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
<location_type>ROOFTOP</location_type>
<viewport>
<southwest>
<lat>37.4188514</lat>
<lng>-122.0874526</lng>
</southwest>
<northeast>
<lat>37.4251466</lat>
<lng>-122.0811574</lng>
</northeast>
</viewport>
</geometry>
</result>
</GeocodeResponse>
And the following object
[DataContract(Namespace = "")]
public class GeocodeResponse
{
[DataMember(Name = "status", Order = 1)]
public string Status { get; set; }
[DataMember(Name = "result", Order = 2)]
public List<Result> Results { get; set; }
[DataContract(Name = "result", Namespace = "")]
public class Result
{
[DataMember(Name = "geometry")]
public CGeometry Geometry { get; set; }
[DataContract(Name = "geometry", Namespace = "")]
public class CGeometry
{
[DataMember(Name = "location")]
public CLocation Location { get; set; }
[DataContract(Name = "location", Namespace = "")]
public class CLocation
{
[DataMember(Name = "lat", Order = 1)]
public double Lat { get; set; }
[DataMember(Name = "lng", Order = 2)]
public double Lng { get; set; }
}
}
}
}
I am trying to deserialize using the following method
DataContractSerializer serializer = new DataContractSerializer(typeof(GeocodeResponse));
var response = (GeocodeResponse)serializer.ReadObject(request.GetResponse().GetResponseStream());
After deserialization, Results is always empty. What am I doing wrong?
UPDATE:
Changed Result element. Getting another error now:
There was an error deserializing the object of type GeocodeResponse. The data at the root level is invalid. Line 1, position 1.
...
[DataMember(Name = "result", Order = 2)]
public CResult Result { get; set; }
[DataContract]
public class CResult
{
...
I am able to Deserialize the original object using JSON like below.
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(GeocodeResponse));
You can't really use the DataContractSerializer
(DCS) to deserialize the response from that request, you need to use the XmlSerializer
. DCS doesn't support unwrapped collections, which is what the response contains - like the one shown below.
<a>
<b/>
<c/>
<c/>
<c/>
</a>
The DCS only supports collections when they're wrapped in their own element:
<a>
<b/>
<cs>
<c/>
<c/>
<c/>
</cs>
</a>
The XmlSerializer
does support such collections. The code below shows a partial class structure for deserializing a response from the Google geocoding XML.
public class StackOverflow_7521821
{
[XmlRoot(ElementName = "GeocodeResponse", Namespace = "")]
public class GeocodeResponse
{
[XmlElement(ElementName = "status")]
public GeocodeResponseStatusCode Status;
[XmlElement(ElementName = "result")]
public List<GeocodeResponseResult> Results;
}
[XmlType(Namespace = "")]
public class GeocodeResponseResult
{
[XmlElement(ElementName = "type")]
public List<string> Types;
[XmlElement(ElementName = "formatted_address")]
public string FormattedAddress;
[XmlElement(ElementName = "address_component")]
public List<GeocodeResponseAddressComponent> AddressComponents;
[XmlElement(ElementName = "geometry")]
public GeocodeResponseResultGeometry Geometry;
}
[XmlType(Namespace = "")]
public class GeocodeResponseAddressComponent
{
[XmlElement(ElementName = "long_name")]
public string LongName;
[XmlElement(ElementName = "short_name")]
public string ShortName;
[XmlElement(ElementName = "type")]
public List<string> Types;
}
[XmlType(Namespace = "")]
public class GeocodeResponseResultGeometry
{
[XmlElement(ElementName = "location")]
public Location Location;
[XmlElement(ElementName = "location_type")]
public GeocodeResponseResultGeometryLocationType LocationType;
[XmlElement(ElementName = "viewport")]
public GeocodeResponseResultGeometryViewport Viewport;
}
[XmlType(Namespace = "")]
public class GeocodeResponseResultGeometryViewport
{
[XmlElement(ElementName = "southwest")]
public Location Southwest;
[XmlElement(ElementName = "northeast")]
public Location Northeast;
}
public enum GeocodeResponseStatusCode
{
OK,
ZERO_RESULTS,
OVER_QUERY_LIMIT,
REQUEST_DENIED,
INVALID_REQUEST,
}
public enum GeocodeResponseResultGeometryLocationType
{
ROOFTOP,
RANGE_INTERPOLATED,
GEOMETRIC_CENTER,
APPROXIMATE,
}
[XmlType(Namespace = "")]
public class Location
{
[XmlElement(ElementName = "lat")]
public string Lat;
[XmlElement(ElementName = "lng")]
public string Lng;
}
public static void Test()
{
XmlSerializer xs = new XmlSerializer(typeof(GeocodeResponse));
WebClient c = new WebClient();
byte[] response = c.DownloadData("http://maps.googleapis.com/maps/api/geocode/xml?address=1+Microsoft+Way,+Redmond,+WA&sensor=true");
MemoryStream ms = new MemoryStream(response);
GeocodeResponse geocodeResponse = (GeocodeResponse)xs.Deserialize(ms);
Console.WriteLine(geocodeResponse);
c = new WebClient();
response = c.DownloadData("http://maps.googleapis.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=true");
ms = new MemoryStream(response);
geocodeResponse = (GeocodeResponse)xs.Deserialize(ms);
Console.WriteLine(geocodeResponse);
}
}