C# 使用 Newtonsoft 解析 JSON

Posted

技术标签:

【中文标题】C# 使用 Newtonsoft 解析 JSON【英文标题】:C# Parsing JSON w/ Newtonsoft 【发布时间】:2016-06-16 06:04:40 【问题描述】:

我对 c# 很陌生,所以如果这没有任何意义,我深表歉意!

使用 C# 控制台应用程序,我很难解析详细的 json 响应并将 json 值分配给变量。我以为我可以通过将 json 反序列化为字符串来完成所有工作,直到大约 200 次迭代(我将对超过一百万个地址进行地理编码),我收到一个空结果数组的响应,导致我的应用程序崩溃。现在我正在尝试使用 JObject、JProperty 和 JToken 的新方法,但运气不佳。

我的 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
        
      
    
  ]

破坏我原始代码的 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": []

原代码..

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.

错误消息是“索引超出范围。必须为非负数且小于集合的大小。”错误发生在“if (array.results[0] != null)”处。


现在我确定这无论如何都不是最好的方法,所以我想我会尝试一些新的东西(在这里找到:C# Parsing JSON array of objects)..

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.
    

这看起来很有希望,除了三件事..

    我不想解析结果[1]。您会在 json 响应中注意到,第二个结果实例的准确度得分较低。而且,当我不更改 lat/lng 值来隐藏我的个人地址时,这两个实例是不同的,第二个的准确度要低得多。

    虽然我成功获取了上述县的值,但我无法获得“formatted_address”的响应,以及每次通过 foreach 循环重置的值。

    在“字段”部分,有多个同名对象。比如……

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

如何选择我要查找的“名称”?学区、时区、国会选区等。

再次抱歉,我发了这么长的帖子。我整个星期都在研究这个问题,就在我以为我已经弄明白的时候,一个愚蠢的地址必须不返回任何结果并破坏一切!!我真的很感谢比我聪明得多的人的帮助......在家工作的缺点,没有其他大脑可供选择:)

【问题讨论】:

您的第一段代码很好,但您应该尝试使用JsonConvert.DeserializeObject&lt;YourType&gt;(string) 反序列化为一个类。这样,您可以静态访问这些值。您可以通过array != null &amp;&amp; array.Length &gt; 0 检查数组中是否至少有一项。希望这会有所帮助! 嗨蒂姆。这是来自 geocod.io 的 Mathias。我们的一位客户分享了他为反序列化响应而编写的这个示例。随时在这里查看:gist.github.com/btompkins/8722291 【参考方案1】:

如果您查看破坏代码的数据:


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

您将results 定义为一个空数组。换句话说,它包含零个元素。因此,尝试访问此数组中的第一个元素(在索引 0 处)会导致您遇到错误。

而不是你正在做的测试:

if (array.results[0] != null)

   // cont.

你应该这样做:

if (array.Length != 0)

   // cont.

这是因为“结果”对象存在,但它是空的(长度为零)。

【讨论】:

以上是关于C# 使用 Newtonsoft 解析 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何用c#解析这个json(使用Newtonsoft.Json)?

C# unity (发布到安卓端中使用)解析json字符串—使用微软官方的包Newtonsoft.Json

C# unity (发布到安卓端中使用)解析json字符串—使用微软官方的包Newtonsoft.Json

C# unity (发布到安卓端中使用)解析json字符串—使用微软官方的包Newtonsoft.Json

C# Newtonsoft.Json解析json字符串处理 - JToken 用法

C# Newtonsoft.Json.dll json数据格式上传下载解析