6

I've got a JSON stream coming back from a server, and I need to search for a specific value of the node "ID" using JSON.net to parse the data. And I can almost make it work, but not quite because the results coming back are deeply nested in each other -- this is due to the fact that I'm getting a folder structure back. I've boiled the JSON down to a much simpler version. I'm getting this:

{
    "data": {
        "id": 0,
        "name": "",
        "childFolders": [{
            "id": 19002,
            "name": "Locker",
            "childFolders": [{
                "id": 19003,
                "name": "Folder1",
                "childFolders": [],
                "childComponents": [{
                    "id": 19005,
                    "name": "route1",
                    "state": "STOPPED",
                    "type": "ROUTE"
                }]
            }, {
                "id": 19004,
                "name": "Folder2",
                "childFolders": [],
                "childComponents": [{
                    "id": 19008,
                    "name": "comm1",
                    "state": "STOPPED",
                    "type": "COMMUNICATION_POINT"
                }, {
                    "id": 19006,
                    "name": "route2",
                    "state": "STOPPED",
                    "type": "ROUTE"
                }, {
                    "id": 19007,
                    "name": "route3",
                    "state": "STOPPED",
                    "type": "ROUTE"
                }]
            }],
            "childComponents": []
        }],
        "childComponents": []
    },
    "error": null
}

I can almost get there by going:

var objects = JObject.Parse(results);
var subobjects = objects["data"]["childFolders"][0]["childFolders"][1];

I can see in the debug view that it'll parse the object, but won't let me search within.

My ultimate goal is to be able to search for "route3" and get back 19007, since that's the ID for that route. I've found some results, but all of them assume you know how far nested the object is. The object I'm searching for could be 2 deep or 20 deep.

3 Answers 3

11

My ultimate goal is to be able to search for "route3" and get back 19007

You can use linq and Descendants method of JObject to do it:

var dirs = JObject.Parse(json)
            .Descendants()
            .Where(x=>x is JObject)
            .Where(x=>x["id"]!=null && x["name"]!=null)
            .Select(x =>new { ID= (int)x["id"], Name = (string)x["name"] })
            .ToList();

var id = dirs.Find(x => x.Name == "route3").ID;
Sign up to request clarification or add additional context in comments.

2 Comments

Since all we're really interested in is the ID, this can be simplified: var id = JObject.Parse(json).Descendants().OfType<JObject>().Where(x => (string)x["name"] == "route3" && x["id"] != null).Select(x => (int)x["id"]).FirstOrDefault();
This worked beautifully - thank you for writing this.
10

You can use the SelectToken or SelectTokens functions to provide a JPath to search for your desired node. Here is an example that would provide you the route based on name:

JObject.Parse(jsonData)["data"].SelectToken("$..childComponents[?(@.name=='route3')]")

You can find more documentation on JPath here

Comments

4

Simply write a recursive function:

private Thing FindThing(Thing thing, string name)
{
    if (thing.name == name)
        return thing;
    foreach (var subThing in thing.childFolders.Concat(thing.childComponents))
    {
        var foundSub = FindThing(subThing, name);
        if (foundSub != null)
            return foundSub;
    }
    return null;
}

class RootObject
{
    public Thing data { get; set; }
}

class Thing
{
    public int id { get; set; }
    public string name { get; set; }
    public List<Thing> childFolders { get; set; } = new List<Thing>();
    public List<Thing> childComponents { get; set; } = new List<Thing>();
}

And using it:

var obj = JsonConvert.DeserializeObject<RootObject>(jsonString);
var result = FindThing(obj.data, "route3");

1 Comment

is that a Thing?

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.