简体   繁体   English

C#使用Newtonsoft解析JSON

[英]C# Parsing JSON w/ Newtonsoft

I'm very new to c#, so I apologize if this doesn't make any sense! 我是C#的新手,所以如果这没有任何意义,我深表歉意!

Using a C# console application, I'm having a hard time parsing a detailed json response and assigning json values to variables. 使用C#控制台应用程序,我很难解析详细的json响应并将json值分配给变量。 I thought I had everything working by deserializing the json to a string until about 200 iterations in (I'll be geocoding over a million addresses), I received a response with an empty result array that crashed my application. 我以为我可以通过将json反序列化为字符串来完成所有工作,直到大约进行200次迭代(我将对一百万个地址进行地理编码),然后收到一个响应,其中包含空结果数组,这使我的应用程序崩溃了。 Now I'm trying a new approach using JObject, JProperty, and JToken, but not having much luck. 现在,我正在尝试使用JObject,JProperty和JToken的新方法,但是运气不佳。

My json example is is follows .. 我的json示例如下。

{
  "input": {
    "address_components": {
      "number": "123",
      "predirectional": "E",
      "street": "Main",
      "suffix": "St",
      "formatted_street": "E Main St",
      "city": "Mesa",
      "state": "AZ",
      "zip": "85209",
      "country": "US"
    },
    "formatted_address": "123 E Main St, Mesa, AZ 85209"
  },
  "results": [
    {
      "address_components": {
        "number": "123",
        "predirectional": "E",
        "street": "Main",
        "suffix": "St",
        "formatted_street": "E Main Ave",
        "city": "Mesa",
        "county": "Maricopa County",
        "state": "AZ",
        "zip": "85209",
        "country": "US"
      },
      "formatted_address": "123 E Main St, Mesa, AZ 85209",
      "location": {
        "lat": 33.123456,
        "lng": -111.123456
      },
      "accuracy": 1,
      "accuracy_type": "range_interpolation",
      "source": "TIGER\/Line\u00ae dataset from the US Census Bureau",
      "fields": {
        "congressional_district": {
          "name": "Congressional District 5",
          "district_number": 5,
          "congress_number": "114th",
          "congress_years": "2015-2017"
        },
        "state_legislative_districts": {
          "senate": {
            "name": "State Senate District 16",
            "district_number": "16"
          },
          "house": {
            "name": "State House District 16",
            "district_number": "16"
          }
        },
        "school_districts": {
          "unified": {
            "name": "Gilbert Unified District",
            "lea_code": "0403400",
            "grade_low": "PK",
            "grade_high": "12"
          }
        },
        "timezone": {
          "name": "MST",
          "utc_offset": -7,
          "observes_dst": false
        }
      }
    },
    {
      "address_components": {
        "number": "123",
        "predirectional": "E",
        "street": "Main",
        "suffix": "St",
        "formatted_street": "E Main St",
        "city": "Mesa",
        "county": "Maricopa County",
        "state": "AZ",
        "zip": "85209",
        "country": "US"
      },
      "formatted_address": "123 E Main St, Mesa, AZ 85209",
      "location": {
        "lat": 33.123456,
        "lng": -111.123456
      },
      "accuracy": 0.8,
      "accuracy_type": "range_interpolation",
      "source": "TIGER\/Line\u00ae dataset from the US Census Bureau",
      "fields": {
        "congressional_district": {
          "name": "Congressional District 5",
          "district_number": 5,
          "congress_number": "114th",
          "congress_years": "2015-2017"
        },
        "state_legislative_districts": {
          "senate": {
            "name": "State Senate District 16",
            "district_number": "16"
          },
          "house": {
            "name": "State House District 16",
            "district_number": "16"
          }
        },
        "school_districts": {
          "unified": {
            "name": "Gilbert Unified District",
            "lea_code": "0403400",
            "grade_low": "PK",
            "grade_high": "12"
          }
        },
        "timezone": {
          "name": "MST",
          "utc_offset": -7,
          "observes_dst": false
        }
      }
    }
  ]
}

The json that broke my original code .. 破坏我原始代码的json ..

{
  "input": {
    "address_components": {
      "number": "123",
      "predirectional": "E",
      "street": "Main",
      "suffix": "St",
      "formatted_street": "E Main St",
      "city": "Mesa",
      "state": "AZ",
      "zip": "85209",
      "country": "US"
    },
    "formatted_address": "123 E Main St, Mesa, AZ 85209"
  },
  "results": []
}

The original code .. 原始代码..

Uri uri = new Uri("https://api.geocod.io/v1/geocode?q=" + geocodioAddress + "&fields=cd,stateleg,school,timezone&api_key=" + app_key);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string output = reader.ReadToEnd();
response.Close();

dynamic array = JsonConvert.DeserializeObject(output);

if (array.results[0] != null)
{
    // cont.
}

The error msg was "Index was out of range. Must be non-negative and less than the size of the collection." 错误消息msg为“索引超出范围。必须为非负数并且小于集合的大小。” The error occurs at "if (array.results[0] != null)". 该错误发生在“ if(array.results [0]!= null)”处。


Now I'm sure this isn't the best approach anyways, so I thought I'd try something new (found here: C# Parsing JSON array of objects ) .. 现在,我确定这仍然不是最好的方法,所以我想尝试一些新方法(可在此处找到: C#解析JSON对象数组 )。

Uri uri = new Uri("https://api.geocod.io/v1/geocode?q=" + geocodioAddress + "&fields=cd,stateleg,school,timezone&api_key=" + app_key);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string json = reader.ReadToEnd();
response.Close();

var resultObjects = AllChildren(JObject.Parse(json))
    .First(c => c.Type == JTokenType.Array && c.Path.Contains("results"))
    .Children<JObject>();

foreach (JObject result in resultObjects)
{
    foreach (JProperty property in result.Properties())
    {
        JToken _county = property.Value.SelectToken("county");
        string county = Convert.ToString(_county);

        // cont.
    }
}

This looked really promising, except for three things.. 除了三件事,这看起来确实很有希望。

  1. I don't want to parse results[1]. 我不想解析结果[1]。 You'll notice in the json response, that the second results instance has a lower accuracy score. 您会在json响应中注意到,第二个结果实例的准确性得分较低。 And when I don't change the lat/lng values to hide my personal address, these two instances are different with the 2nd being much less accurate. 而且,当我不更改经/纬度值来隐藏我的个人地址时,这两个实例就不同了,而第二个实例的准确性要差得多。

  2. While I successfully got the value for the county above, I can't get a response for "formatted_address", as well as the value resets each time through the foreach loop. 虽然我成功获取了上面的县的值,但我无法获得“ formatted_address”的响应,并且每次通过foreach循环都会重置该值。

  3. In the "fields" section, there are multiple objects with the same name. 在“字段”部分中,有多个具有相同名称的对象。 For example.. 例如..

    JToken _county = property.Value.SelectToken("name"); JToken _county = property.Value.SelectToken(“ name”);

How do I select which "name" I'm looking for? 如何选择要查找的“名称”? school district, timezone, congressional district, etc.. 学区,时区,国会区等。

Again, I'm sorry for such a long post. 同样,对于这么长的帖子,我感到抱歉。 I've been working on this all week, and just when I thought I had it figured out, one stupid address has to return no results and break everything!! 我整整一周都在努力,就在我以为自己想通了的时候,一个愚蠢的地址必须不返回任何结果并破坏一切! I really appreciate the help of people much smarter than me ... the downside of working from home, no other brains to pick :) 我真的很感谢比我聪明的人们的帮助...在家工作的弊端,没有其他人才可以选择:)

If you look at the data that broke your code: 如果查看破坏代码的数据:

{
 {
   "input": {
   ..
   },
  "formatted_address": "123 E Main St, Mesa, AZ 85209"
  },
 "results": []  
}

You have results defined as an empty array. 您将results定义为空数组。 In other words it contains zero elements. 换句话说,它包含零个元素。 Thus trying to access the first element (at index 0) in this array results in the error that you are getting. 因此,尝试访问此数组中的第一个元素(索引为0)会导致您得到错误。

Instead of the test that you are doing: 代替正在执行的测试:

if (array.results[0] != null)
{
   // cont.
}

you should do: 你应该做:

if (array.Length != 0)
{
   // cont.
}

this is because the 'results' object exists, but it is empty (length is zero). 这是因为存在“结果”对象,但该对象为空(长度为零)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM