JContainer, JObject, JToken and Linq confusion - c#

I am having trouble understanding when to use JContainer, JObject, and JToken. I understand from the "standards" that JObject is composed of JProperties and that JToken is the base abstract class for all of the JToken types, but I don't understand JContainer.
I am using C# and I just bought LinqPad Pro 5.
I have a JSON data source in a file, so I'm deserializing that file's contents successfully using this statement:
string json;
using (StreamReader reader = new StreamReader(#"myjsonfile.json"))
{
json = reader.ReadToEnd();
}
At that point, I take the JSON string object and deserialize it to a JObject (and this might be my mistake--perhaps I need to make jsonWork a JToken or JContainer?):
JObject jsonWork = (JObject)JsonConvert.DeserializeObject(json);
In my JSON data (the string represented by JSON), I have three objects--the top-level object look similar to this:
{
"Object1" : { ... },
"Object2" : { ... },
"Object3" : { ... }
}
Each object is composed of all sorts of tokens (arrays, strings, other objects, etc.), so it is dynamic JSON. (I used ellipses as placeholders rather than muddying up this question wit lots of JSON data.)
I want to process "Object1", "Object2", and "Object3" separately using LINQ, however. So, ideally, I would like something like this:
// these lines DO NOT work
var jsonObject1 = jsonWork.Children()["Object1"]
var jsonObject2 = jsonWork.Children()["Object2"]
var jsonObject3 = jsonWork.Children()["Object3"]
But the above lines fail.
I used var above because I have no idea what object type I should be using: JContainer, JObject, or JToken! Just so you know what I want to do, once the above jsonObject# variables are properly assigned, I would like to use LINQ to query the JSON they contain. Here is a very simple example:
var query = from p in jsonObject1
where p.Name == "Name1"
select p
Of course, my LINQ ultimately will filter for JSON arrays, objects, strings, etc., in the jsonObject variable. I think once I get going, I can use LinqPad to help me filter the JSON using LINQ.
I discovered that if I use:
// this line WORKS
var jsonObject1 = ((JObject)jsonWork).["Object1"];
Then I get an JObject type in jsonObject1. Is this the correct approach?
It is unclear to me when/why one would use JContainer when it seems that JToken and JObject objects work with LINQ quite well. What is the purpose of JContainer?

You don't really need to worry about JContainer in most cases. It is there to help organize and structure LINQ-to-JSON into well-factored code.
The JToken hierarchy looks like this:
JToken - abstract base class
JContainer - abstract base class of JTokens that can contain other JTokens
JArray - represents a JSON array (contains an ordered list of JTokens)
JObject - represents a JSON object (contains a collection of JProperties)
JProperty - represents a JSON property (a name/JToken pair inside a JObject)
JValue - represents a primitive JSON value (string, number, boolean, null)
So you see, a JObject is a JContainer, which is a JToken.
Here's the basic rule of thumb:
If you know you have an object (denoted by curly braces { and } in JSON), use JObject
If you know you have an array or list (denoted by square brackets [ and ]), use JArray
If you know you have a primitive value, use JValue
If you don't know what kind of token you have, or want to be able to handle any of the above in a general way, use JToken. You can then check its Type property to determine what kind of token it is and cast it appropriately.

JContainer is a base class for JSON elements that have child items. JObject, JArray, JProperty and JConstructor all inherit from it.
For example, the following code:
(JObject)JsonConvert.DeserializeObject("[1, 2, 3]")
Would throw an InvalidCastException, but if you cast it to a JContainer, it would be fine.
Regarding your original question, if you know you have a JSON object at the top level, you can just use:
var jsonWork = JObject.Parse(json);
var jsonObject1 = jsonWork["Object1"];

Most examples have simple json and I've googled "C# Newtonsoft parse JSON" more than once.
Here's a bit of a json file I was just asked to parse for a csv. The company name value is nested within many arrays / objects so it is semi-complicated in that regard.
{
"page": {
"page": 1,
"pageSize": 250
},
"dataRows": [
{
"columnValues": {
"companyName": [
{
"name": "My Awesome Company",
}
]
}
}
]
}
var jsonFilePath = #"C:\data.json";
var jsonStr = File.ReadAllText(jsonFilePath);
// JObject implementation for getting dataRows JArray - in this case I find it simpler and more readable to use a dynamic cast (below)
//JObject jsonObj = JsonConvert.DeserializeObject<JObject>(jsonStr);
//var dataRows = (JArray)jsonObj["dataRows"];
var dataRows = ((dynamic)JsonConvert.DeserializeObject(jsonStr)).dataRows;
var csvLines = new List<string>();
for (var i = 0; i < dataRows.Count; i++)
{
var name = dataRows[i]["columnValues"]["companyName"][0]["name"].ToString();
// dynamic casting implemntation to get name - in this case, using JObject indexing (above) seems easier
//var name2 = ((dynamic)((dynamic)((dynamic)dataRows[i]).columnValues).companyName[0]).name.ToString();
csvLines.Add(name);
}
File.WriteAllLines($#"C:\data_{DateTime.Now.Ticks}.csv", csvLines);

Related

Get Key Name from nested json object

I am new to C# and JSON and need some help in getting the Key name(s) in a list of a nested JSON object. The keys are dynamic so I won't necessarily know the keys.
sample code I've tried.
```
protected void test()
{
var mystring = #"{
""zone1"": {
""sites"": {
""site1"": {
""to"": ""email1"",
""subject"": ""subjecttxt"",
""link"": ""somesite""
},
""site2"": {
""to"": ""email1"",
""subject"": ""subject"",
""link"": ""somesite""
}
},
""zone2"": {
""to"": ""email1"",
""subject"": ""subject"",
""link"": ""somelink""
}}";
var rss = JObject.Parse(mystring);
foreach (var section in rss)
{
Console.Write(section.Key);
IList<JToken> result = rss["zone1"]["sites"].Children().ToList();
var zone = section.Key;
var site = rss[zone]["sites"];
foreach (var subsite in rss["zone1"]["sites"])
{
var subs = subsite.Parent.ToString();
// some other code
}
}
}
```
Looking for a result:
site1,
site2,
...
I can get the children as IList but looking for something similar to "section.Key" as noted above.
Thank you for your help.
I believe what you are looking for is to get the properties of the sites. Since accessing the rss["zone1"]["sites"] returns a JToken, you will need to convert that to JObject and then use Properties() method to get the data you need.
var sites = ((JObject)rss["zone1"]["sites"]).Properties();
Then you can simply iterate over the IEnumerable<Jproperty> to get the Name of the property or whatever else you need from under it.
To get the section.Key for the sites, you can use the following code.
foreach(var site in (JObject)rss["zone1"]["sites"]) {
Console.WriteLine(site.Key);
}
Output:
site1
site2
Your first call to JObject.Parse already does all the work of converting a string into a structured JSON object. The currently-accepted answer redoes some of this work by (1) turning a structured JSON object back into a string, and then (2) re-parsing it with JObject.Parse. There is a simpler way.
Instead, you can cast the value stored at rss["zone1"]["sites"] into a JObject. (The expression rss["zone1"]["sites"] has type JToken, which is a parent class of JObject, but in this case we happen to know that rss["zone1"]["sites"] is always JSON object, i.e. a collection of key-value pairs. Therefore, this cast is safe to perform.)
This is what the code might look like:
var sites = (JObject) rss["zone1"]["sites"];
foreach (var site in sites)
{
Console.WriteLine(site.Key);
}

Generic method to parse json of any structure (nth depth) c#

Have to write a generic method which will take json of any structure and add new properties to each element with data
Structure # 1, (Person)
Input Json data,
{'name':'sam', 'age': 12}
Expected output,
{'name':'sam', 'name_xyz': 'Rob', 'age': 12, 'age_xyz': 15}
Structure # 2, (Person with address)
Input json data,
{ 'name': 'sam', address : { 'city': 'fishers', 'zip': 23456 } }
Expected output,
{'name': 'sam', 'name_xyz': 'rob', address : { 'city': 'fishers', 'city_xyz': 'fishers', 'zip': 23456, 'zip_xyz': 678768} }
Structure # 3 (Person's)
Input json data,
[{'name': 'sam'}, {'name':'rex'}]
Expected Output,
[{'name': 'sam', 'name_xyz': 'felix'}, {'name':'rex', 'name_xyz' : 'bob'}]
I have something for defined model using NewtonSoft, but I need generic method to parse and evaluate any type of json data.
var jsonData = JsonConvert.SerializeObject(modelData);
var jArray = JArray.Parse(jsonData) as JArray;
dynamic persons = jArray;
foreach (dynamic person in persons)
{
var name = person.name;
var newname = Getnewname(name);
person.Add(new JProperty("name_xyz", newname));
var age = person.age;
var newage = GetnewAge(age);
person.Add(new JProperty("age_xyz", newage));
}
var result = persons.ToString();
Things to consider,
Look for each node, determine if it is array or object
Found object, create new object at same level with same property post fix '_xyz'
Found Array, loop through each object and same step 2
It will be nth level depth
I have encountered a similar situation and I solved it using a "nested dictionary" approach. While it is always a pleasure to work in the comfort zone of strongly typed entities, there are times when creating C# classes might get too cumbersome. This was my situation.
Treat the entire JSON like a dictionary where one or more keys might store another Dictionary. And this might continue several levels deep. The method Jobject.Parse worked for me. The JObject works like a key-value collection and you can recursively retrieve more JObject instances as you traverse deeper.
Newtonsoft reference - flat dictionary
https://www.newtonsoft.com/json/help/html/SerializingCollections.htm
This will NOT work very well with a nested structure like yours.
Newtonsoft code snippet - parsing as a JObject
string json="[{'name': 'sam', 'name_xyz': 'felix'}, {'name':'rex', 'name_xyz' : 'bob'}]"
JObject o = JObject.Parse(json);
https://www.newtonsoft.com/json/help/html/ParseJsonObject.htm
Newtonsoft reference - JObject
https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JObject.htm
More examples on using JObject as opposed to hard typing
https://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm

Get multiple values on JSON with Json.NET

Is there a function where you can select multiples "nodes" on JSON string?
Sample:
var myJson = #"{
'channel' : 'nine',
'segment' : 'mobile',
'food' : 'pizza'
}";
var myObjectFromJson = JObject.Parse(myJson);
var channelFoodNodes = myObjectFromJson.SelectTokens("channel, food"); //<- This call not works!
Expected result:
{
"channel" : "nine",
"food" : "pizza"
}
Reference:
Querying JSON with SelectToken
First, your code is invalid with the newlines (your string should be a verbatim string if you want to put newlines in it without concatenating, with # in front of it, and quotes replaced by double quotes).
Second, you are trying to invoke SelectTokens() on a string... you need to parse it to a JObject first:
var myJson = JObject.Parse(#"
{
""channel"" : ""nine"",
""segment"" : ""mobile"",
""food"" : ""pizza""
}");
Then myJson is a JObject (and not a string) where you can call SelectTokens() on
HOWEVER, what you want to achieve can't be achieved with JPath (which is what SelectTokens() uses), so you'd be better off parsing the object directly, something like:
var channelFoodNodes = myJson.Children()
.OfType<JProperty>()
.Where(x => new []{ "channel", "food"}.Contains(x.Name));
Then you can construct a new JObject from the resulting enumerable of JProperties:
var newObject = new JObject(channelFoodNodes);
Which will contain your resulting object.
You can see it all in action in this fiddle
If you want to select the properies this way (as you were trying to do with SelectTokens()), you can also build a simple extension method:
public static IEnumerable<JProperty> SelectRootProperties(this JObject obj, params string[] propertyNames)
{
return obj.Children().OfType<JProperty>().Where(x => propertyNames.Contains(x.Name));
}
And call it like:
myObject.SelectRootProperties("channel", "food");
See it in action in this other fiddle
(or you could also make a simple method which gets the input json string and the property names, construct the JObject, parse the properties and return the string of the resulting object, which seems to be what you are asking, but I'll leave that as an exercise)
Your existing data is a key/value of strings. You can deserialize it to a Dictionary<string, string> and access the pieces you want from the dictionary produced.
var things = JsonConvert.DeserializeObject<Dictionary<string,string>>(json);
Console.WriteLine(things["channel"]);
Console.WriteLine(things["food"]);

asp.net - How to get / deserialize object of JsonPatchDocument?

I could serialize the JsonPatchDocument model by using JsonConvert.SerializeObject(), but the type of result is string, how can I convert it to normal array type? Or how to get JsonPatchDocument object straight to array?
var pathSerialized = JsonConvert.SerializeObject(patch);
Console.WriteLine(pathSerialized);
// Result as string:
// "[{"value":"2018-08-30","path":"/openTo","op":"replace"},{"value":"2018-04-01","path":"/openFrom","op":"replace"}]"
You don't have to serialize the JsonPatchDocument object at all. You can access its properties directly through the object. For example filtering for the path property:
var elementsWithPath = patch.Operations.Where(o => o.path.Equals("some path"));
I think you might be looking to do something with JTokens from the Newtonsoft.Json.Linq namespace. You can turn the pathserialized string into a JToken with var jToken = JToken.Parse(pathSerializer), then explore the underlying objects and properties by enumerating them with var childTokens = jToken.Children().
One of those child tokens is going to be a JObject, which is a Json representation of an object. You can access properties of a JObject with jObject["propertyName"].

Easily working on a json object

I'm deserializing (or parsing) a json string to a c# object (using Json.NET) and getting a JObject. I want to iterate all the properties with the key "bla", in the same way iterating all xml elements that named "bla" with XElement.Elements("bla").
If it's not possible, I would like to deserialize my json string into a c# object, and work dynamically and recursively on my deserialized json object (my json string can have lists / arrays that can have objects of 2 types.
In the end after editing my object (changing values and removing or adding properties) I need to serialize my object back to a json string.
Which is the best and easiest way to use json serializing and deserializing?
my Json looks like this:
{"Families":{"Family":[{"propA":"dhsj", "propB":"dhdisb"}, {"propA":"krbsbs", "propC":"ksndbd", "propD":"odndns", "Families":{"Family":[....]}}, {"propA":"dhsj", "propB":[{"propA":"dhsj", "propB":"dhdisb"}, {"propA":"krbsbs", "propC":"ksndbd", "propD":"odndns", "Families":{"Family":[....]}}, {"propA":"dhsj", "propB":"fghfgh"}]}]}
in conclusion, the json value is a json object that it's value is a list/array, the list/array can contain 2 "types" of objects, and one of these types also has a property which it's value is a json object that it's value is a list/array, and it goes like this recursively. sometimes the value of one of the props of the type that doesn't have a property which it's value is a json object that it's value is a list/array, can be a list/array itself, that can contain only 1 type of the two mentioned.
If you don't need a strongly-typed object, you can deserialize to a dictionary:
Dictionary<string, object> myObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
And then just use it as a dictionary:
myObject["Property"] = value;
Or
foreach(var propertyKey in myObject.Keys)
{
// do something with each property
Console.WriteLine($"{propertyKey} = {myObject[propertyKey]}");
}
Here's a fiddle
You can serialize it back after you are done
My json looks more like this:
{"Familys":{"Family":[{"propA":"dhsj", "propB":"dhdisb"}, {"propA":"krbsbs", "propC":"ksndbd", "propD":"odndns", "Families":{"Family":[....]}}]}
For JSON like this:
var json = #"{
""Families"":{
""Family"":[
{
""propA"":""Top""
},
{
""propA"":""Top.Lower"",
""Families"":{
""Family"":[
{
""propB"":""propB value""
},
{
""propA"":""Top.Lower.EvenLower"",
""Families"":{
""Family"":[
{
""propA"":""Top.Lower.EvenLower.EvenLower""
}
]
}
}
]
}
}
]
}
}";
Do something like this:
//calling code makes use of "dynamic" to make things clean and readable.
dynamic parsedJson = JsonConvert.DeserializeObject(json);
var allPropAValues = GetPropAValues(parsedJson);
//**** NOTE: this has our extra property ****
var jsonWithExtraStuffProperty = JsonConvert.SerializeObject(parsedJson);
//recursive function that reads AND writes properties
public static List<string> GetPropAValues(dynamic obj)
{
var propAValues = new List<string>();
//**** NOTE: the use of an added property ****
obj.ExtraStuff = new Random().Next();
//if we have a propA value, get it.
if (obj.propA != null)
propAValues.Add(obj.propA.Value);
//iterate through families if there are any. your JSON had Families.Family.
if (obj.Families != null)
foreach (dynamic family in obj.Families.Family)
propAValues.AddRange(GetPropAValues(family));
return propAValues;
}

Categories