1

I'm trying to parse this json string

{ 
   "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"
      }
   ]
}

I can access the metadata elements using this code:

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>();
}

But when I try to access any of the remaining elements, I get a Null exception. Let me use the User Profile element to show what I do. The first is similar to above:

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);
   }
}

The number of elements in each lookup group can change so I loop from 0 until I get an empty descr.

Maybe there is a better way to do this?

3
  • 6
    Do yourself and any future developer a favor and specify a model to deserialize the JSON to. Something like this shown in the Newtonsoft JSON help, or use something like Json2CSharp or QuickType Commented Oct 25, 2019 at 8:39
  • Thanks for the answers. I got it working as I finally saw that the base level had multiple layers even though their structure was quite different. Commented Oct 29, 2019 at 7:35
  • Models seem to be the way forward. Does that also work if my JSON isn't static? Additional properties might get added to the features layer and more elements might get added to the lookups? I guess I'll post this as a new question to better understand the options Commented Oct 29, 2019 at 7:37

3 Answers 3

1

Since you loop through the object you can't access "lookups" when the itteration is currently at the "metadata" child. Therefor a check is required before accessing the data:

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

But I highly reccomend to create a model for your Json Parsing, which will make your life way easier.

Sign up to request clarification or add additional context in comments.

Comments

1

This code does not check for null

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

The col might not exist in the JSON file. Better check if it is null first before calling the ToObject

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

My suggestion.

Comments

1

The different elements you are trying to access (metadata, lookups, features) are in seperate layers. If you are navigating a layer where you can access metadata, you will not be able to access lookups in that same layer. You have to move to the next layer where you have all lookups.

Example:

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>();

        }
    }
}

In addition to that, also what Thai Anh Duc said, you can not perform .ToObject on an object that is null so you will have to check that beforehand (also in the example).

And lastly, the comment from MindSwipe is a much better way of parsing Json, you should not do that manually but rather use a model to parse your Json into.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.