2016-03-03 9 views
0

Я очень новичок в C#, поэтому прошу прощения, если это не имеет никакого смысла!C# Parsing JSON w/Newtonsoft

Использование консольного приложения 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");

Как выбрать, какое «имя» я ищу? школьный округ, часовой пояс, район Конгресса и т. д.

Опять же, я прошу прощения за такой длинный пост. Я работаю над этим всю неделю, и только когда я подумал, что это выяснилось, один глупый адрес не должен возвращать никаких результатов и сломать все! Я очень ценю помощь людей гораздо умнее меня ... обратная сторона работы из дома, другие мозгов, чтобы забрать :)

+0

Ваш первый бит кода хорош, но вы должны попробовать десериализовать класс, используя 'JsonConvert.DeserializeObject (string)'. Таким образом, вы можете получить доступ к значениям статически. Вы можете проверить, есть ли хотя бы один элемент массива, выполнив 'array! = Null && array.Length> 0'. Надеюсь это поможет! –

+0

Привет Тим. Это Матиас из geocod.io. Один из наших клиентов разделил этот пример, который он написал для десериализации ответа. Не стесняйтесь проверить здесь: https://gist.github.com/btompkins/8722291 – CodeMonkey

ответ

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. 
} 

это потому, что объект «Результаты» существует, но он пуст (длина равна нулю) ,