Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I iterate through nested dictionaries with JSON.NET?

I have a JSON structure that I would like to manually parse to a POCO object using JSON.NET.

The JSON structure is a bunch of nested dictionaries... The root dictionary contains categories, the next level contains products within those categories and the last level contains versions of those products.

{
        "category-1": {
           "product-1": {
              "product-version-1": {
                   "id":1,
                   ...
               }
            }
        },
        "category-2": {
           "product-2": {
              "product-version-2": {
                   "id":2,
                   ...
               }
            },
            "product-3": {
               "product-version-3": {
                   "id":3,
                   ...
                }
            }
         }
}

I would like to parse this structure, keeping in mind the keys of all the dictionaries are not known to me ahead of time.

This was the code that I had written (I was going to convert to LINQ once it worked...) - I expected this to work with a couple of nested loops but clearly JTokens and JObjects don't work the way I thought... Id is always null.

var productsJObject = JObject.Parse(result.Content.ReadAsStringAsync().Result);

foreach (var category in productsJObject)
{
    foreach (var product in category.Value)
    {
        foreach (var version in product)
        {
            var poco = new Poco
                      {
                          Id = version.SelectToken("id").ToString()
                      };
        }
    }
}

So my question, how can I iterate over nested dictionaries using JSON.Net?

like image 560
Tyler Avatar asked Jan 23 '12 05:01

Tyler


1 Answers

Found this question trying to figure out how to parse JSON.NET in C#. Hopefully my answer will help someone else...

I wrote this code to help me parse a random JSON object and analyze the structure. It's somewhat rough and probably doesn't handle all scenarios, but it does the trick. Right now its just storing locations in a dictionary, but it should be pretty easy to see what its doing and modify it to do what you want:

static void Main(string[] args)
{
    Dictionary<string, string> nodes = new Dictionary<string, string>();

    // put your JSON object here
    JObject rootObject = JObject.Parse("{\"world\": {\"hello\": \"woo\", \"foo\": \"bar\", \"arr\": [\"one\", \"two\"]}}");

    ParseJson(rootObject, nodes);

    // nodes dictionary contains xpath-like node locations
    Debug.WriteLine("");
    Debug.WriteLine("JSON:");
    foreach (string key in nodes.Keys)
    {
        Debug.WriteLine(key + " = " + nodes[key]);
    }
}

/// <summary>
/// Parse a JSON object and return it as a dictionary of strings with keys showing the heirarchy.
/// </summary>
/// <param name="token"></param>
/// <param name="nodes"></param>
/// <param name="parentLocation"></param>
/// <returns></returns>
public static bool ParseJson(JToken token, Dictionary<string, string> nodes, string parentLocation = "")
{
    if (token.HasValues)
    {
        foreach (JToken child in token.Children())
        {
            if (token.Type == JTokenType.Property)
                parentLocation += "/" + ((JProperty)token).Name;
            ParseJson(child, nodes, parentLocation);
        }

        // we are done parsing and this is a parent node
        return true;
    }
    else
    {
        // leaf of the tree
        if (nodes.ContainsKey(parentLocation))
        {
            // this was an array
            nodes[parentLocation] += "|" + token.ToString();
        }
        else
        {
            // this was a single property
            nodes.Add(parentLocation, token.ToString());
        }

        return false;
    }
}
like image 149
hross Avatar answered Oct 19 '22 23:10

hross