【问题标题】:C# Parsing JSON w/ NewtonsoftC# 使用 Newtonsoft 解析 JSON
【发布时间】: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. 我不想解析结果[1]。您会在 json 响应中注意到,第二个结果实例的准确度得分较低。而且,当我不更改 lat/lng 值来隐藏我的个人地址时,这两个实例是不同的,第二个的准确度要低得多。

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

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

    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

标签: c# arrays json foreach json.net


【解决方案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.
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多