使用C#中的Datacontract反序列化Google地理编码XML

时间:2011-09-22 21:38:41

标签: c# xml xml-serialization deserialization datacontractserializer

我有以下Google地理编码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>

以下对象

[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; }
            }
        }
    }
}

我正在尝试使用以下方法反序列化

DataContractSerializer serializer = new DataContractSerializer(typeof(GeocodeResponse));

var response = (GeocodeResponse)serializer.ReadObject(request.GetResponse().GetResponseStream());

反序列化后,结果始终为空。我究竟做错了什么?

更新:

更改了结果元素。现在又出现了另一个错误:

反序列化GeocodeResponse类型的对象时出错。根级别的数据无效。第1行,第1位。

...

    [DataMember(Name = "result", Order = 2)]
    public CResult Result { get; set; }

    [DataContract]
    public class CResult
    {
    ...

我可以使用JSON反序列化原始对象,如下所示。

DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(GeocodeResponse));

2 个答案:

答案 0 :(得分:2)

您无法真正使用DataContractSerializer(DCS)反序列化该请求的响应,您需要使用XmlSerializer。 DCS不支持解包的集合,这是响应所包含的 - 如下所示。

<a>
  <b/>
  <c/>
  <c/>
  <c/>
</a>

当DCS包装在他们自己的元素中时,它只支持集合:

<a>
  <b/>
  <cs>
    <c/>
    <c/>
    <c/>
  </cs>
</a>

XmlSerializer确实支持此类集合。下面的代码显示了用于反序列化来自Google地理编码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);
    }
}

答案 1 :(得分:0)

如果只有一个List<Result>标记,其中包含所有内容,则您不想使用<result>。我从测试代码中删除了ListResults不再为空。