Разбор строки json с помощью Newtonsoft вызывает исключение ссылки Null - PullRequest
1 голос
/ 25 октября 2019

Я пытаюсь разобрать эту строку json

{ 
   "layers":[ 
      { 
         "metadata":{ 
            "cells":2, "records":42887000, "dataset":"uk_da", "query":"155ms", "sample":10, "calibrate":100
         }
      },
      { 
         "lookups":{ 
            "User Profile":{ 
               "p_0":"Resident", "p_1":"Worker", "p_2":"Visitor"
            },
            "Age Group":{ 
               "a_0":"0 to 14", "a_1":"15 to 30", "a_2":"30 to 45", "a_3":"45 to 60", "a_4":"60 plus"
            },
            "Prosperity Band":{ 
               "w_0":"very low", "w_1":"low", "w_2":"medium", "w_3":"high"
            },
            "Visits":{ 
               "v_0":"total"
            }
         }
      },
      { 
         "features":[ 
            { 
               "properties":{ 
                  "h3":"83194afffffffff",
                  "v_0":8000, "a_0":2000, "a_1":0, "a_2":2000, "a_3":0, "a_4":4000,
                  "w_0":2000, "w_1":2000, "w_2":1000, "w_3":3000, "p_0":3000, "p_1":0, "p_2":5000
               },
               "type":"Feature"
            },
            { 
               "properties":{ 
                  "h3":"83194efffffffff",
                  "v_0":42879000, "a_0":13189000, "a_1":726000, "a_2":20372000, "a_3":1550000, "a_4":6828000,
                  "w_0":6604000, "w_1":17373000, "w_2":10544000, "w_3":8144000, "p_0":27705000, "p_1":2180000, "p_2":12994000
               },
               "type":"Feature"
            }
         ],
         "type":"FeatureCollection"
      }
   ]
}

Я могу получить доступ к элементам метаданных с помощью этого кода:

dynamic dynObj = Newtonsoft.Json.JsonConvert.DeserializeObject(responseBody);
foreach (var layer in dynObj.layers)
{
   _numCells = (int)layer["metadata"]["cells"].ToObject<int>();
   _numRecords = (int)layer["metadata"]["records"].ToObject<int>();
   _queryTime = (string)layer["metadata"]["query"].ToObject<string>();
   _sample = (int)layer["metadata"]["sample"].ToObject<int>();
   _calibrate = (int)layer["metadata"]["calibrate"].ToObject<int>();
}

Но когда я пытаюсь получить доступ к любому из оставшихсяэлементы, я получаю исключение Null. Позвольте мне использовать элемент профиля пользователя, чтобы показать, что я делаю. Первый аналогичен приведенному выше:

dynamic dynObj = Newtonsoft.Json.JsonConvert.DeserializeObject(responseBody);
foreach (var layer in dynObj.layers)
{
   _numCells = (int)layer["metadata"]["cells"].ToObject<int>();
   _numRecords = (int)layer["metadata"]["records"].ToObject<int>();
   _queryTime = (string)layer["metadata"]["query"].ToObject<string>();
   _sample = (int)layer["metadata"]["sample"].ToObject<int>();
   _calibrate = (int)layer["metadata"]["calibrate"].ToObject<int>();

   string group = "User Profile";

   for (int i = 0; ; i++)
   {
      string col = String.Format("p_{0}", i.ToString());
      string descr = (string)layer["lookups"][group][col].ToObject<string>();
      if (descr == string.Empty)
         break;

      _lstColGroup.Add(group);
      _lstColNames.Add(col);
      _lstColDescriptions.Add(descr);
   }
}

Количество элементов в каждой группе поиска может изменяться, поэтому я повторяю цикл от 0 до получения пустого описания.

Может быть, есть лучший способсделать это?

Ответы [ 3 ]

1 голос
/ 25 октября 2019

Различные элементы, к которым вы пытаетесь получить доступ (метаданные, поиск, функции), находятся в отдельных слоях. Если вы перемещаетесь по слою, где вы можете получить доступ к метаданным, вы не сможете получить доступ к поискам в этом же слое. Вы должны перейти к следующему слою, где у вас есть все поиски.

Пример:

dynamic dynObj = Newtonsoft.Json.JsonConvert.DeserializeObject(source);
foreach (var layer in dynObj.layers)
{
    if (layer["metadata"] != null)
    {
        int _numCells = (int)layer["metadata"]["cells"].ToObject<int>();
        int _numRecords = (int)layer["metadata"]["records"].ToObject<int>();
        string _queryTime = (string)layer["metadata"]["query"].ToObject<string>();
        int _sample = (int)layer["metadata"]["sample"].ToObject<int>();
        int _calibrate = (int)layer["metadata"]["calibrate"].ToObject<int>();
    }
    else if (layer["lookups"] != null)
    {

        string group = "User Profile";

        for (int i = 0; ; i++)
        {
            string col = String.Format("p_{0}", i.ToString());
            if (layer["lookups"][group][col] == null)
                break;
            string descr = (string)layer["lookups"][group][col].ToObject<string>();

        }
    }
}

В дополнение к тому, что, как сказал Thai Anh Duc, нельзя выполнять .ToObject onобъект, который является нулевым, так что вам придется проверить это заранее (также в примере).

И, наконец, комментарий от MindSwipe - намного лучший способ синтаксического анализа Json, вы не должны делать это вручную, а скорееиспользуйте модель для разбора вашего Json.

1 голос
/ 25 октября 2019

Поскольку вы перебираете объект, вы не можете получить доступ к «поискам», когда изменение находится в данный момент у дочернего элемента «метаданных». Поэтому перед доступом к данным требуется проверка:

Newtonsoft.Json.Linq.JObject obj = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(responseBody);
foreach (var item in obj.SelectToken("layers"))
{
    if (item.SelectToken("metadata") != null) { // Stuff with metadata }
    if (item.SelectToken("lookups") != null) { // Stuff with lookups }
    if (item.SelectToken("features") != null) { // Stuff with features }
}

Но я настоятельно рекомендую создать модель для вашего анализа Json, которая облегчит вашу жизнь.

1 голос
/ 25 октября 2019

Этот код не проверяет наличие нуля

string descr = (string)layer["lookups"][group][col]

col может отсутствовать в файле JSON. Лучше сначала проверить, является ли оно нулевым, прежде чем вызывать ToObject

var descNode = layer["lookups"][group][col];
if(descNode == null)
   break;
string descr = descNode.ToObject<string>();
if(string.IsNullOrEmpty(descr))
   break;

Мое предложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...