在C#中解析Bing地图API的JSON代码

5
我使用必应地图 REST API,因为我想从一个特定位置找到地理位置。该 URL 能够很好地工作,但由于这是我第一次使用 JSON 代码,我不太清楚如何获得我想要的输出。
我尝试了以下方法:
string URL = "http://dev.virtualearth.net/REST/v1/Locations?countryRegion=&adminDistrict=&locality=Wien&postalCode=&addressLine=&userLocation=&userIp=&usermapView=&includeNeighborhood=&maxResults=&key=MY_KEY";
WebClient client = new WebClient();
client.OpenReadAsync(new Uri(URL, UriKind.Absolute));
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);

private void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Point));
    Point data = serializer.ReadObject(e.Result) as Point;
}

[DataContract]
public class Point
{
    /// <summary>
    /// Latitude,Longitude
    /// </summary>
    [DataMember(Name = "coordinates")]
    public double[] Coordinates { get; set; }
}

当我在浏览器中输入链接时,我的回应如下:
{"authenticationResultCode":"ValidCredentials","brandLogoUri":"http://dev.virtualearth.net/Branding/logo_powered_by.png","copyright":"Copyright © 2013 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.","resourceSets":[{"estimatedTotal":1,"resources":[{"__type":"Location:http://schemas.microsoft.com/search/local/ws/rest/v1","bbox":[47.253395080566406,-123.16571807861328,47.946159362792969,-121.50344085693359],"name":"Seattle, WA","point":{"type":"Point","coordinates":[47.603561401367188,-122.32943725585938]},"address":{"adminDistrict":"WA","adminDistrict2":"King Co.","countryRegion":"United States","formattedAddress":"Seattle, WA","locality":"Seattle"},"confidence":"High","entityType":"PopulatedPlace","geocodePoints":[{"type":"Point","coordinates":[47.603561401367188,-122.32943725585938],"calculationMethod":"Rooftop","usageTypes":["Display"]}],"matchCodes":["Good"]}]}],"statusCode":200,"statusDescription":"OK","traceId":"08bee37ecb714d7cb7e2783eb8f873a4|LTSM000177|02.00.183.2300|LTSIPEVM000039"}
我的问题是:这样做是否正确?我该如何获取数据?
我希望你能帮助我,我已经花了很多时间解决这个问题。
-----编辑-----
现在我使用JSON.net,但我不知道如何将从网站获取的数据解析为字符串变量。
我尝试了以下内容:
var json = new WebClient().DownloadString("url");

但是这并不行,因为我正在开发Windows Phone应用。

System.Net.WebClient没有包含“DownloadString”的定义...

有人可以帮我让它在Windows Phone应用中运行吗?


Crusader633,能否请您提供一下绑定JSON以在Bing地图上显示位置的代码示例? - A.Goutam
4个回答

7

在处理json时,我更喜欢使用Json.Net库。在声明必要的类之后,以下代码即可实现。

var root = JsonConvert.DeserializeObject<RootObject>(json);

foreach (var rs in root.resourceSets)
{
    foreach (var r in rs.resources)
    {
        Console.WriteLine(r.point.coordinates[0] + " , " + r.point.coordinates[1]);
    }
}

您可以使用此网站将您的JSON转换为具体类。
public class Point
{
    public string type { get; set; }
    public List<double> coordinates { get; set; }
}

public class Address
{
    public string adminDistrict { get; set; }
    public string adminDistrict2 { get; set; }
    public string countryRegion { get; set; }
    public string formattedAddress { get; set; }
    public string locality { get; set; }
}

public class GeocodePoint
{
    public string type { get; set; }
    public List<double> coordinates { get; set; }
    public string calculationMethod { get; set; }
    public List<string> usageTypes { get; set; }
}

public class Resource
{
    public string __type { get; set; }
    public List<double> bbox { get; set; }
    public string name { get; set; }
    public Point point { get; set; }
    public Address address { get; set; }
    public string confidence { get; set; }
    public string entityType { get; set; }
    public List<GeocodePoint> geocodePoints { get; set; }
    public List<string> matchCodes { get; set; }
}

public class ResourceSet
{
    public int estimatedTotal { get; set; }
    public List<Resource> resources { get; set; }
}

public class RootObject
{
    public string authenticationResultCode { get; set; }
    public string brandLogoUri { get; set; }
    public string copyright { get; set; }
    public List<ResourceSet> resourceSets { get; set; }
    public int statusCode { get; set; }
    public string statusDescription { get; set; }
    public string traceId { get; set; }
}

Json.net 还允许您使用 dynamic 关键字而无需声明任何这些类。

dynamic root = JsonConvert.DeserializeObject(json);

foreach (var rs in root.resourceSets)
{
    foreach (var r in rs.resources)
    {
        Console.WriteLine(r.point.coordinates[0] + " , " + r.point.coordinates[1]);
    }
}

谢谢,这看起来非常不错,我明天会测试它。 - Crusader633

3
您可以使用Microsoft的JSON序列化/反序列化工具。
如果您没有使用ASP.NET,您需要包含System.Web和System.Web.Extensions引用;
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
Dictionary<string, object> json = (object[])javaScriptSerializer.DeserializeObject(text);

您无需将其映射到类或结构的集合,数组将转换为object[],对象将转换为Dictionary。
要查看生成的Dictionary json的内容,您可以使用Visual Studio Inspector,或直接访问内容并记住元素如何映射。
例如,要访问brandLogoUri,只需:
(string)json["brandLogoUri"]

为了循环 resourceSets(一个数组),你需要按照以下步骤操作。
foreach(Dictionary<string,object> key in (Dictionary<string,object>)json["resourceSets"])
{
...do your stuff here...
}

显然,您的代码可读性会变差,但如果将json映射到类太困难,或者想要即时测试某些内容,则这种方法很有用。


谢谢,但我该如何将URL中的JSON转换为字符串。这是我现在遇到的主要问题,在我的编辑中已经清楚描述了。 - Crusader633
2
抱歉,我错过了编辑。您必须使用该方法的“async”版本。WebClient webClient = new WebClient(); webClient.DownloadStringCompleted += (sender, e) => { ... 在此处解析您的json ... }; webClient.DownloadStringAsync(new Uri("...在此处输入您的uri..."));我没有直接测试过它,但应该可以工作。 http://msdn.microsoft.com/en-us/library/system.net.downloadstringcompletedeventargs.aspx - Daniele Salvatore Albano
请勿使用JSON.net,因为我在解码仅包含数字键的对象的JSON时遇到了一些奇怪的问题,例如{ "a": { 1: "hello", 2: "world", 3: "!" } }(我没有测试最新版本)。 - Daniele Salvatore Albano

2
您可以使用http://json2csharp.com/生成自定义类。将其包含在项目代码中。然后,使用相同的DataContractJsonSerializer与新的CustomClass。
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CustomClass));
CustomClass data = serializer.ReadObject(e.Result);

如果你使用 VS2012,你可以在工具中找到: http://blogs.msdn.com/b/webdev/archive/2012/12/18/paste-json-as-classes-in-asp-net-and-web-tools-2012-2-rc.aspx,这个工具可以让你将 JSON 数据转换成 C# 类。

1
我知道你正在使用必应地图,但这里也有谷歌的解决方案:
使用C#请求Google Map API并解析DirectionsResponse,将url中的json更改为xml,并使用以下代码将结果转换为可用的C#泛型列表对象。
var url = String.Format("http://maps.googleapis.com/maps/api/directions/xml?...");
var result = new System.Net.WebClient().DownloadString(url);
var doc = XDocument.Load(new StringReader(result));

var DirectionsResponse = doc.Elements("DirectionsResponse").Select(l => new
{
    Status = l.Elements("status").Select(q => q.Value).FirstOrDefault(),
    Route = l.Descendants("route").Select(n => new
    {
        Summary = n.Elements("summary").Select(q => q.Value).FirstOrDefault(),
        Leg = n.Elements("leg").ToList().Select(o => new
        {
            Step = o.Elements("step").Select(p => new
            {
                Travel_Mode = p.Elements("travel_mode").Select(q => q.Value).FirstOrDefault(),
                Start_Location = p.Elements("start_location").Select(q => new
                {
                    Lat = q.Elements("lat").Select(r => r.Value).FirstOrDefault(),
                    Lng = q.Elements("lng").Select(r => r.Value).FirstOrDefault()
                }).FirstOrDefault(),
                End_Location = p.Elements("end_location").Select(q => new
                {
                    Lat = q.Elements("lat").Select(r => r.Value).FirstOrDefault(),
                    Lng = q.Elements("lng").Select(r => r.Value).FirstOrDefault()
                }).FirstOrDefault(),
                Polyline = p.Elements("polyline").Select(q => new
                {
                    Points = q.Elements("points").Select(r => r.Value).FirstOrDefault()
                }).FirstOrDefault(),
                Duration = p.Elements("duration").Select(q => new
                {
                    Value = q.Elements("value").Select(r => r.Value).FirstOrDefault(),
                    Text = q.Elements("text").Select(r => r.Value).FirstOrDefault(),
                }).FirstOrDefault(),
                Html_Instructions = p.Elements("html_instructions").Select(q => q.Value).FirstOrDefault(),
                Distance = p.Elements("distance").Select(q => new
                {
                    Value = q.Elements("value").Select(r => r.Value).FirstOrDefault(),
                    Text = q.Elements("text").Select(r => r.Value).FirstOrDefault(),
                }).FirstOrDefault()
            }).ToList(),
            Duration = o.Elements("duration").Select(p => new
            {
                Value = p.Elements("value").Select(q => q.Value).FirstOrDefault(),
                Text = p.Elements("text").Select(q => q.Value).FirstOrDefault()
            }).FirstOrDefault(),
            Distance = o.Elements("distance").Select(p => new
            {
                Value = p.Elements("value").Select(q => q.Value).FirstOrDefault(),
                Text = p.Elements("text").Select(q => q.Value).FirstOrDefault()
            }).FirstOrDefault(),
            Start_Location = o.Elements("start_location").Select(p => new
            {
                Lat = p.Elements("lat").Select(q => q.Value).FirstOrDefault(),
                Lng = p.Elements("lng").Select(q => q.Value).FirstOrDefault()
            }).FirstOrDefault(),
            End_Location = o.Elements("end_location").Select(p => new
            {
                Lat = p.Elements("lat").Select(q => q.Value).FirstOrDefault(),
                Lng = p.Elements("lng").Select(q => q.Value).FirstOrDefault()
            }).FirstOrDefault(),
            Start_Address = o.Elements("start_address").Select(q => q.Value).FirstOrDefault(),
            End_Address = o.Elements("end_address").Select(q => q.Value).FirstOrDefault()
        }).ToList(),
        Copyrights = n.Elements("copyrights").Select(q => q.Value).FirstOrDefault(),
        Overview_polyline = n.Elements("overview_polyline").Select(q => new
        {
            Points = q.Elements("points").Select(r => r.Value).FirstOrDefault()
        }).FirstOrDefault(),
        Waypoint_Index = n.Elements("waypoint_index").Select(o => o.Value).ToList(),
        Bounds = n.Elements("bounds").Select(q => new
        {
            SouthWest = q.Elements("southwest").Select(r => new
            {
                Lat = r.Elements("lat").Select(s => s.Value).FirstOrDefault(),
                Lng = r.Elements("lng").Select(s => s.Value).FirstOrDefault()
            }).FirstOrDefault(),
            NorthEast = q.Elements("northeast").Select(r => new
            {
                Lat = r.Elements("lat").Select(s => s.Value).FirstOrDefault(),
                Lng = r.Elements("lng").Select(s => s.Value).FirstOrDefault()
            }).FirstOrDefault(),
        }).FirstOrDefault()
    }).FirstOrDefault()
}).FirstOrDefault();

我希望这能帮助到某些人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接