JSON.NET - Recognizing a nested array - c#

I have this code for getting values out of a json string.
var json = #"[{""property"":""Status"",""value"":""val""}]";
var jArray = JArray.Parse(json);
foreach (JToken jToken in jArray)
{
var property = jToken.Value<string>("property");
var value = jToken.Value<string>("value");
}
This works perfect for the provided input. But in some situations the value property may contain an array.
var json = #"[{""property"":""Status"",""value"":[1,2]}]";
I'd like to check somehow if the value contains a simple value or an array. If the value is an array then bind it to a collection.
Is this possible using JSON.net ?

dynamic value = jToken["value"];
if (value is JArray)
// do something
(you could use object instead of dynamic in my example, but dynamic might be easier to work with later)

Related

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"].

Json.NET Convert model to array and return to JObject

I am having trouble finding the JObject nested keys in order to convert the key values to an array. The code below seems to only get the parent keys instead of the entire object.
What I want: Convert any ValuesToList items in the JObject to JArray if they are not already an array irregardless of how nested the keys are. NOTE: Solution should work with entirely different Json models.
Purpose: Sometimes the Json returns as a model instead of an array which causes deserializing to a model to throw exceptions.
result = {{ "errors": null, "content": { "officeId": 1, "daysClosed": [] } }}
// values in ValuesToList are "content" and "daysClosed"
var result = JObject.Parse(_responseString);
foreach (string item in ValuesToList.ToArray())
{
// Check to see if toList value is contained in the JObject.
if (result[item] != null)
{
// Check to see if the value is an array. If not, will convert to array/list Json.
if (!(result[item] is JArray))
result[item] = new JArray(result[item]);
}
}
The problem is that I am unable to find daysClosed in the JObject because it is a child. Thus, when item = "daysClosed" the result[item] will return null.
I was working on a way to use reflection to solve this problem but ran into issues where a new JObject would be appended to the current JObject and I am looking to replace the Keys values with an array if the keyvalue exists and is not already an array.
Since your keys can occur at any depth in the JObject, you'll need to use SelectTokens along with a JsonPath expression to find them. Something like this should work:
foreach (string item in ValuesToList.ToArray())
{
// find all occurrences of the item in the JObject at any depth
foreach (JToken match in result.SelectTokens("$.." + item))
{
// if the matching token is not an array, wrap it in an array
if (match.Type != JTokenType.Array)
{
JProperty parent = (JProperty)match.Parent;
parent.Value = new JArray(match);
}
}
}
Fiddle: https://dotnetfiddle.net/EtDqNs
why don't you try doing this:
var arrayProperties = result.DoSomething().OfType<JProperty>().Where(prop => prop.Value.Type == JArray);

JContainer, JObject, JToken and Linq confusion

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);

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;
}

Retrieving an array from JSON in ASP.net C#

I'm gathering data from a web API which returns a complex JSON string. This contains values of many different types, a few arrays, and some fairly deep nesting.
Currently I'm converting the string to a dynamic object like so:
dynamic dynamicObject = JsonConvert.DeserializeObject(jsonString);
Then I'm retrieving values from this object as needed and typecasting them, however this method gives a null reference exception when I attempt to retrieve an array:
int myValue = (int)dynamicObject.foo.value; // Works!
int[] myArrayOfInts = (int[])dynamicObject.bar.values; // Null
I'm not sure how to proceed as I'm fairly new to C# and ASP.net. Most of the solutions I have come across so far require the creation of small, strictly-typed classes which mirror the entire JSON structure. In my case it would be preferable to simply use a dynamic object, partly for simplicity and partly because only certain values are actually being used.
When I try to run your code, I get a RuntimeBinderException: Cannot convert type 'Newtonsoft.Json.Linq.JArray' to 'int[]'. You can do this conversion with ToObject.
dynamic dynamicObject = JsonConvert.DeserializeObject("{\"values\": [1, 3, 4]}");
int[] myArrayOfInts = dynamicObject.values.ToObject<int[]>();
The cast to int works because a casting conversion is defined for many types including int, but not int[].
You could deserialize the array using the ToObject<type> extension method (where type is the desired data type):
var jsonString = #"{ ""name"":""test"", ""array"": [""10"",""20"",""30"",""40""] }";
dynamic dynamicObject = JsonConvert.DeserializeObject(jsonString);
Console.WriteLine(((string)dynamicObject.name));
var items = dynamicObject.array.ToObject<int[]>();
foreach (var item in items)
{
Console.WriteLine(item);
}
The output is:
test
10
20
30
40
Another possibility would be to cast the object to JObject and then fetch the array as a property - the retrieved object is automatically of type JToken, which allows iteration:
var array = ((JObject)dynamicObject)["array"];
foreach (var item in array)
{
Console.WriteLine(item.ToString());
}

Categories