this is further to my question here
JSON.NET - Confusion in getting Parent from JToken
I am still having problems in understanding how to discover the parent in JSON.NET
So Now I have this JSON Document
{
"attributes": {"attr0":"value0"},
"children" : {
"ProductA" : {
"attributes": {"attr1":"value1", "attr2":"value2"},
"children" : {
"ProductC":{
"attributes": {"attr3":"value3", "attr4":"value4"},
"children" : {
"ProductD":{
"attributes": {"attr7":"value7", "attr8":"value8"},
"children" : {
"ProductE":{
"attributes": {"attr9":"value9", "attr10":"value10"},
"children" : {},
"referencedChildren" : {}
}
},
"referencedChildren" : {}
}
},
"referencedChildren" : {}
}
},
"referencedChildren" : {}
},
"ProductB" : {
"attributes": {"attr5":"value5", "attr6":"value6"},
"children" : {},
"referencedChildren" : {}
}
},
"referencedChildren" : {}
}
Based on this I have written this code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
namespace JSonTest {
class Program {
static void Main(string[] args) {
string content = File.ReadAllText(@"c:\temp\foo.txt");
JObject token = JObject.Parse(content);
JToken p2 = token["children"]["ProductA"]["children"]["ProductC"]["children"]["ProductD"]["children"]["ProductE"];
JToken parent = p2;
do {
parent = GetParentModule(parent);
Console.WriteLine(((JProperty)parent).Name);
} while (parent != null);
}
private static JToken GetParentModule(JToken token) {
JToken retVal = token;
int i = 5;
while (i > 0) {
retVal = retVal.Parent;
if (retVal == null) {
break;
} else {
--i;
}
}
return retVal;
}
}
}
When I run this code, the first call to GetParentModule return "ParentD"... but the second call does not return "ParentC"
My objective here is that when I call GetParentModule on ProductE it returns ProductD and when I call GetParentModule on ProductD it returns ProductC and when I call GetParentModule on ParentC it returns ProductA.
In my previous thread I found that 5 calls to Parent, returned me the parent correctly. but in subsequent calls I see that "4" calls to Parent returns the "ProductC".
Can you please explain what is going on and how can walk up the parent hierarchy successfully?
I think you are confused because of two factors working against you in concert:
token["property"] simplifies downward traversal of the JSON by abstracting away the actual structure to better fit your mental model. But, there is no such convenience for navigating upward, so you are exposed to all the extra layers.Let's take a simplified example of your JSON and explore what's going on in a little more detail. Say we have this JSON:
{
"children": {
"ProductA": {
"children": {
"ProductC": {
"attribute": "some stuff"
}
}
}
}
}
In your mental model you have this:
But the Json.Net object model works like this:
JObject is a collection of JProperty objects.JProperty is a name-value pair, where the name is string and the value is either a JObject, JValue or JArray.JObject are its JProperties.JProperty is its value.So the actual in-memory representation of the JSON is:
When you do something like this:
JObject productA = (JObject)top["children"]["ProductA"];
these extra layers are hidden from you. It looks just as if each object (or property) is nested directly in the one above it. But don't be fooled. Under the covers, this indexer syntax is really just a shortcut for this equivalent code:
JObject productA = (JObject)top.Children<JProperty>()
.First(prop => prop.Name == "children")
.Value
.Children<JProperty>()
.First(prop => prop.Name == "ProductA")
.Value;
Hopefully by now it should be clear what is going on, and we can get back to your real question, which is how to go up the chain and get the desired result. For example, say we have a reference to product C and we want to get product A (or more exactly, we have a reference to the JObject that is the value of the JProperty whose name is "ProductC", and we want to go up the chain to get the value of the JProperty whose name is "ProductA"). How can we do that?
Well, again, if you look at the actual Json.Net structure, you can see a pattern to it. Each JObject that you've identified as a "product" is inside a JProperty with an "interesting" name that is not "children". And if that product has a "parent product", it will have an ancestor JProperty whose name is "children". And the parent of that JProperty is the one you want.
So in other words, all you need to do is walk upward until you find the first JProperty whose name is "children", then take the parent of that JProperty, and that should be the JObject you are looking for.
In code:
private static JToken GetParentModule(JToken token)
{
while (token != null &&
(token.Type != JTokenType.Property ||
((JProperty)token).Name != "children"))
{
token = token.Parent;
}
return (token != null ? token.Parent : null);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With