1

I'm having a hard time getting the parent key/property/attribute of my JSON objects using JSON.net. That is, I want the outermost property name, as a string, without knowing beforehand/visually what it is. I'm currently iterating over a set of KeyValuePair items and attempting to, for each of those, log out the parent from something that looks like

{"parentKey": 
 {
  "Name": "Name",
  "Id": "123",
  "Other": null,
  "nestedArr": 
   [
    "idx0", 
    "idx1",
    "idx2"
   ]
 }
}

I've tried both keyValue.Value.Ancestors() and keyValue.Value.Parent. With the former, I'm getting what looks to be the function definition... I'm actually not sure what it is: Newtonsoft.Json.Linq.JToken+<GetAncestors>d_ _ 42. Completely beffuddled by that, because based on the usage examples I've scrounged up here, I'm using it to standard.

With the latter, I log out the entire object, or else what appears to be the entire preceding KeyValuePair, rather than just the string "parentKey", which is what I want. The JSON.net docs aren't the best as far as explicit usage examples and what to expect (or maybe it's just that being new to C#, I can't make sense of them), but in any case, I'm kind of unclear on why this is happening and how to accomplish what I want. This is what I'm trying:

foreach (var keyValue in jObjList[0])  //jObjList is a List<JObject> defined above
{
    Console.WriteLine(keyValue.Value.Ancestors());
    Console.WriteLine(keyValue.Value.Parent);
    if (keyValue.Value.GetType() == typeof(JObject))//same block goes for if it's typeof(JArray)
    {
      Console.WriteLine(keyValue.Key);
    }
}

Edit: in the JSON given, and within the loop defined above, for example, in order to get my parent keys (that's just what I'm calling them), my code simply says, if (keyValue.Value.GetType() == typeof(JObject), write keyValue.Key to the console, and the same goes for if getType() is a JArray. In either case, keyValue.Key is a parent key, if that makes sense. What I mean to say by this is that it is a property that points to another Array or Object. My issue is that, as I'm doing this loop recursively, when I get down to a nested Array or Object, my code has no way of realizing that, although there is a new "parent key" currently, like with nestedArr, for example, the parent key of nestedArr is still "parentKey".

the code is abridged, but that's the idea.

All clarifications and corrections are welcome and appreciated. Thanks.

spb
  • 4,049
  • 6
  • 22
  • 30

1 Answers1

4

You are seeing Newtonsoft.Json.Linq.JToken+<GetAncestors>d_ _ 42 for Console.WriteLine(keyValue.Value.Ancestors()) because Ancestors is an IEnumerable<T> whose evaluation is lazy, rather than an explicit collection. What you are seeing is the ToString() output of the not-yet-evaluated enumerable.

If what you want to do is to climb up the parent list of a given JToken and find the lowest parent that has a "parentKey" property, then get the value of that parentKey, then this is how you would do it:

    JToken token = keyValue.Value; // Here I'm declaring JToken explicitly for clarity.  Normally I would use var token = ...

    var parentKey = token.AncestorsAndSelf()     // Climb up the json container parent/child hierachy
        .Select(p => p.SelectToken("parentKey")) // Get the "parentKey" property in the current parent (if present)
        .FirstOrDefault(k => k != null);         // Return the first one found.

    Console.WriteLine(parentKey);

Update

To get the name of the JSON property highest in the JSON container hierarchy, you would do:

    var name = token.AncestorsAndSelf() // Walk up the list of ancestors
        .OfType<JProperty>()            // For each that is a property
        .Select(p => p.Name)            // Select the name
        .LastOrDefault();               // And return the last (topmost).

Update 2

If you're looking for the first property name that appears in a JSON file, you can do the following, using JContainer.DescendantsAndSelf():

    var json = @"[{""parentKey"": 
     {
      ""Name"": ""Name"",
      ""Id"": ""123"",
      ""Other"": null,
      ""nestedArr"": 
       [
        ""idx0"", 
        ""idx1"",
        ""idx2""
       ]
     }
    }]";

    var root = (JContainer)JToken.Parse(json);
    var name = root.DescendantsAndSelf() // Loop through tokens in or under the root container, in document order. 
        .OfType<JProperty>()             // For those which are properties
        .Select(p => p.Name)             // Select the name
        .FirstOrDefault();               // And take the first.

    Debug.WriteLine(name); // Prints "parentKey"

(JContainer represents a JSON node that can contain child nodes, such as an object or array.)

dbc
  • 104,963
  • 20
  • 228
  • 340
  • i don't really understand how the lambdas are working in your example. could you maybe comment on what's going on there? also, I need a way to access "parentKey" kind of anonymously, if you will. I don't know what "parentKey" will be, so I can't pass it as a parameter. I just need to know in a dynamic fashion what the outermost property of a keyValuePair is. I'll edit my Q for clarity. – spb Feb 01 '16 at 19:03
  • @spb - If you can edit your question to include a complete example of your JSON and what you what to print to the console, I can probably explain more clearly. – dbc Feb 01 '16 at 19:13
  • thanks for commenting out the code. :) really helpful. hopefully my edits shed some light on what i'm trying to accomplish/what i'm working with – spb Feb 01 '16 at 19:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102279/discussion-between-spb-and-dbc). – spb Feb 01 '16 at 19:43