3

I am trying to access all the categories in the first level within a Foursquare response:-

{
    "meta": {
        "code": 200
    },
    "response": {
        "categories": [{
            "id": "4d4b7104d754a06370d81259",
            "name": "Arts & Entertainment",
            "pluralName": "Arts & Entertainment",
            "shortName": "Arts & Entertainment",
            "icon": {
                "prefix": "https:\/\/foursquare.com\/img\/categories\/arts_entertainment\/default_",
                "sizes": [32, 44, 64, 88, 256],
                "name": ".png"
            },
            "categories": [{
                "id": "4bf58dd8d48988d1e1931735"

using JSON.NET:-

JObject o = JObject.Parse(FoursquareObject.GetCategories());
IList<string> categories = o.SelectToken("categories[0]").Select(s => (string)s).ToList();

Where FoursquareObject.GetCategories() returns the response as a string. I also tried:-

JArray categories = (JArray)o["categories"];

var categories = (string) o["response[0].categories"];

...and numerous variations of, just to see the response in the variable and always get 'Object reference' or 'cannot be {null}' errors. I know I'm close, but for the life of me can't work out how to get at the 'categories' part of the response...

Can anyone point me in the right direction?

Help is appreciated. ;)

UPDATE:

Thanks to the answers from L.B and Meklarian, I added this code (and variants of):-

dynamic four = JsonConvert.DeserializeObject(FoursquareObject.GetCategories());
        foreach (var cat in four)
        {
            context.Response.Write(cat.response.categories.id);
        }

But regardless of what I try in the Write(), I always get:-

'Newtonsoft.Json.Linq.JProperty' does not contain a definition for 'response'

I tried loads of combinations, no-luck. I checked the output from the JSON file, I get pure JSON response as a string. Just a note, that categories can exist in categories, hence why the JSON seems to look broken. I assure you it's not. I'm completely stuck!

dooburt
  • 3,010
  • 10
  • 41
  • 59
  • 1
    This link may be helpful http://stackoverflow.com/questions/9522044/trying-to-consume-smartystreets-json-with-json-net-cannot-deserialize-json-a/9522266#9522266 – L.B Mar 01 '12 at 22:29
  • @L.B this certainly seems to be just the ticket! +1 – dooburt Mar 01 '12 at 22:30

3 Answers3

3

There are multiple ways to parse this; but in the style you've initially presented, you should try accessing it with [] indexers.

Note that your data has a root object with two properties, meta and response. Assuming response can't be null, you can access categories from it directly like this:

var root = JObject.Parse(/* your json string here */);
var categories = root["response"]["categories"];
var firstCategory = categories[0];

Note that you can use strings matching property names to descend into nested levels, and integers to index into arrays in scope.

Here is the rest of a sample program that can parse the json snippet you've provided.

using System.Windows.Forms;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

namespace _4sqCatResponse
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            if(dlg.ShowDialog() != DialogResult.OK){return;}
            string json = System.IO.File.ReadAllText(dlg.FileName);

            var root = JObject.Parse(json);
            var categories = root["response"]["categories"];
            var firstCategory = categories[0];
            Console.WriteLine("id: {0}", firstCategory["id"]);
            Console.WriteLine("name: {0}", firstCategory["name"]);
            Console.WriteLine("pluralName: {0}", firstCategory["pluralName"]);
            Console.WriteLine("shortName: {0}", firstCategory["shortName"]);
            var icon = firstCategory["icon"];
            Console.WriteLine("icon.prefix: {0}", icon["prefix"]);
            Console.WriteLine("icon.sizes[0]: {0}", icon["sizes"][0]);
            Console.WriteLine("icon.name: {0}", icon["name"]);

            Console.ReadKey();
        }
    }
}

Also I'm a little confused by your json sample; I think you may have overlaid part of your sample or cut something out as you have categories nested in categories. If there is indeed a 2nd level categories inside your categories element and that's what you want, you can access it with this:

var categories2 = root["response"]["categories"][0]["categories"][0];
Console.WriteLine("inner categories id: {0}", categories2["id"]);

Here is the json source I used to test, copied from yours but with closing } and ] marks where needed to make it parse.

{
    "meta": {
        "code": 200
    },
    "response": {
        "categories": [{
            "id": "4d4b7104d754a06370d81259",
            "name": "Arts & Entertainment",
            "pluralName": "Arts & Entertainment",
            "shortName": "Arts & Entertainment",
            "icon": {
                "prefix": "https:\/\/foursquare.com\/img\/categories\/arts_entertainment\/default_",
                "sizes": [32, 44, 64, 88, 256],
                "name": ".png"
            },
            "categories": [{
                "id": "4bf58dd8d48988d1e1931735"
                }]
            }]
    }
}
meklarian
  • 6,595
  • 1
  • 23
  • 49
  • After experimenting with both answers, this lead me down the right path and I solved the problem. Thank you to you both for your answers. – dooburt Mar 04 '12 at 16:05
1

I think this should work

dynamic four2 = JsonConvert.DeserializeObject(FoursquareObject.GetCategories());
foreach(var cat in four2.response.categories)
{
    Console.WriteLine(cat.id + " " + cat.name + " " + cat.icon.prefix);
}
L.B
  • 114,136
  • 19
  • 178
  • 224
0

Use http://json2csharp.com/ to generate C# classes, use RootObject and then access the individual venues

Ravindra
  • 21
  • 3