2
votes

I have no issue deserializing JSON into known types or into Dictionary objects, but what about cases where I don't know what the input is going to be? Specifically I'm referring to receiving a JSON string that represents a flat or nested set of key-value pairs:

{ 
  foo: 'bar',
  baz: 42
}

or

{
  foo: 
  {
    bar: 42,
    baz: ['foo', 'bar', 'baz']
  }
}

But what about cases where the input isn't a key-value-pair, but rather an array, or, an array of objects with other nested objects (including arrays)?

[
  { foo: 'bar', baz: [ 1, 2, 3 ] },
  { foo: 'baz', bar: [ 4, 5, 6 ] }
]

My goal is to have a single class that I could deserialize any of the above into, and then iterate each of its members. The input could be of any structure, so I can't assume the data will come in matching any type I've already defined.

I haven't been able to find a way to do this. Anyone have any guidance?

Edit:

Seems easy enough to JToken.Parse the JSON string; a helpful next step would be to iterate its members and handle JArray and JObject separately.

1
Have you considered deserialising into a dynamic? stackoverflow.com/questions/4535840/…Dr Rob Lang
Yes, I can't seem to get it to work when the input is an array with no key.joelc
What do you mean by an array with no key?Abion47
What you are describing is the LINQ-to-JSON API (JTokens). Use JToken token = JToken.Parse(json). Or if you prefer plain old .Net objects, see How do I use JSON.NET to deserialize into nested/recursive Dictionary and List?Brian Rogers
@joelc I've added an answer which shows how to iterate over the members of a JToken.Brian Rogers

1 Answers

3
votes

What you are describing already exists in Json.Net-- it is the LINQ-to-JSON API (JTokens). Below is an example of using it to parse arbitrary JSON and iterate through the members. Note that you need a recursive method to do it, since the JSON can be nested to any depth.

using Newtonsoft.Json.Linq;
public class Program
{
    public static void Main(string[] args)
    {
        string json1 = @"
        {
          ""foo"": { ""bar"": 42, ""baz"": [ ""a"", ""b"", ""c"" ] }
        }";
        DeserializeAndDump(json1, "example 1");

        string json2 = @"
        [
          { ""foo"": ""bar"", ""baz"": [ 1, 2, 3 ] },
          { ""foo"": ""baz"", ""bar"": [ 4, 5, 6 ] }
        ]";
        DeserializeAndDump(json2, "example 2");
    }

    public static void DeserializeAndDump(string json, string label)
    {
        Console.WriteLine("---- " + label + " ----");
        JToken token = JToken.Parse(json);
        DumpJToken(token);
        Console.WriteLine();
    }

    public static void DumpJToken(JToken token, string indent = "")
    {
        if (token.Type == JTokenType.Object)
        {
            Console.WriteLine(indent + "begin object");
            foreach (JProperty prop in token.Children<JProperty>())
            {
                Console.WriteLine(indent + "  " + prop.Name + ":");
                DumpJToken(prop.Value, indent + "    ");
            }
            Console.WriteLine(indent + "end object");
        }
        else if (token.Type == JTokenType.Array)
        {
            Console.WriteLine(indent + "begin array");
            foreach (JToken child in token.Children())
            {
                DumpJToken(child, indent + "  ");
            }
            Console.WriteLine(indent + "end array");
        }
        else
        {
            Console.WriteLine(indent + token.ToString() + " (" + token.Type.ToString() + ")");
        }
    }
}

Here is the output of the above:

---- example 1 ----
begin object
  foo:
    begin object
      bar:
        42 (Integer)
      baz:
        begin array
          a (String)
          b (String)
          c (String)
        end array
    end object
end object

---- example 2 ----
begin array
  begin object
    foo:
      bar (String)
    baz:
      begin array
        1 (Integer)
        2 (Integer)
        3 (Integer)
      end array
  end object
  begin object
    foo:
      baz (String)
    bar:
      begin array
        4 (Integer)
        5 (Integer)
        6 (Integer)
      end array
  end object
end array

Fiddle: https://dotnetfiddle.net/dfk0sj