Search code examples
c#jsonlinqjson.netlinq-to-json

How to Query and Enumerate complex JSON object using JSON.Net in C#


How can I query (to see if a property exists) and enumerate (the array property) found within a complex JSON object using using JSON.NET in C# ?

I am receiving a complex JSON object from an API with a variable number/type of properties.

I keep reading the JSON.Net Documentation, reviewing samples, etc. but not gotten far and am lost in JObject, JArray, JToken, using dynamic, etc...

I want to find the pageResponses.scriptOutput property, verify it contains and .items[] array and then enumerate/iterate the array.

Edit

I made progress and found typo in JSON data example.

But how can I query/enumerate the child objects using key names, e.g.(item.location, item.timestamp) ?

string json = File.ReadAllText(@"Output.json");
JObject jObj = JObject.Parse(json);

IList<JToken> items = jObj["pageResponses"][0]["scriptOutput"]["items"].ToList();
foreach (JToken item in items){
    Console.WriteLine(item["location"]);
}
/*** Console Output ***/
// Austin, TX
// Anaheim, CA
// Adams, MN
// Barstow, CA

var varItems = from o in jObj["pageResponses"][0]["scriptOutput"]["items"].ToList() select o;

foreach (var item in varItems){
    Console.WriteLine(item["timestamp"]);
}
/*** Console Output ***/
// 2016 - 05 - 03 19:53
// 2016 - 05 - 04 04:10
// 2016 - 05 - 04 08:18
// 2016 - 05 - 01 12:26

(JSON sample below trimmed down for brevity)

{
  "meta": {
    "outputAsJson": true,
    "backend": {
      "os": "linux",
      "id": "10.240.0.3_2",
      "requestsProcessed": 8
    }
  },
  "pageResponses": [
    {
      "pageRequest": {
        "renderType": "script",
        "outputAsJson": true
      },
      "frameData": {
        "name": "",
        "childCount": 1
      },
      "events": [
                  {
                    "key": "navigationRequested",
                    "time": "2016-05-06T13:43:30.344Z"
                  },
                  {
                    "key": "navigationRequested",
                    "time": "2016-05-06T13:43:31.131Z"
                  }
      ],
      "scriptOutput": {
        "items": [
          {
            "location": "Austin, TX",
            "timestamp": "2016-05-03 19:53",
            "title": "User Login"
          },
          {
            "location": "Anaheim, CA",
            "timestamp": "2016-05-04 04:10",
            "title": "User Logout"
          },
          {
            "location": "Adams, MN",
            "timestamp": "2016-05-04 08:18",
            "title": "User Login"
          },
          {
            "location": "Barstow, CA",
            "timestamp": "2016-05-01 12:26",
            "title": "User Logout"
          }
        ]
      },
      "statusCode": 200
    }
  ],
  "statusCode": 200,
  "content": {
    "name": "content.json",
    "encoding": "utf8"
  },
  "originalRequest": {
    "pages": [
      {
        "renderType": "script",
        "outputAsJson": true
      }
    ]
  }
}

Solution

  • I suggest creating a proxy class (I used json2csharp):

    public class Backend
    {
        public string os { get; set; }
        public string id { get; set; }
        public int requestsProcessed { get; set; }
    }
    
    public class Meta
    {
        public bool outputAsJson { get; set; }
        public Backend backend { get; set; }
    }
    
    public class PageRequest
    {
        public string renderType { get; set; }
        public bool outputAsJson { get; set; }
    }
    
    public class FrameData
    {
        public string name { get; set; }
        public int childCount { get; set; }
    }
    
    public class Event
    {
        public string key { get; set; }
        public string time { get; set; }
    }
    
    public class ScriptOutput
    {
        public List<object> items { get; set; }
    }
    
    public class PageRespons
    {
        public PageRequest pageRequest { get; set; }
        public FrameData frameData { get; set; }
        public List<Event> events { get; set; }
        public ScriptOutput scriptOutput { get; set; }
        public int statusCode { get; set; }
    }
    
    public class Content
    {
        public string name { get; set; }
        public string encoding { get; set; }
    }
    
    public class Page
    {
        public string renderType { get; set; }
        public bool outputAsJson { get; set; }
    }
    
    public class OriginalRequest
    {
        public List<Page> pages { get; set; }
    }
    
    public class RootObject
    {
        public Meta meta { get; set; }
        public List<PageRespons> pageResponses { get; set; }
        public int statusCode { get; set; }
        public Content content { get; set; }
        public OriginalRequest originalRequest { get; set; }
    }
    

    Then deserialize it:

    var obj = JsonConvert.DeserializeObject<RootObject>(json);
    if (obj != null && obj.pageResponses != null)
    {
        foreach (var pageResponse in obj.pageResponses)
        {
            if (pageResponse.scriptOutput == null)
                continue;
    
            foreach (var item in pageResponse.scriptOutput.items)
            {
                Console.WriteLine(item);
            }
        }
    }