Iterate IDictionary<string, string> with dynamic nested JSON as value in C# - c#

My application receives Kafka messages that contain a Dictionary<string,string> as one of the properties, and its values could be a nested (however dynamic) json string, and I need to iterate through this unknown json. I am struggling to find a logic and even the best data structure to do this iteration.
Examples of the dictionary (mocked data):
//could have complex nested json string as value
"reward":"{
'xp':'200',
'gp':'150',
'loot':'{
'item':'sword',
'rarity': 'low'
}'
}",
"achievement":"win_match"
// while other messages might be simple
"type":"generic_xp",
"percent":"100",
"status":"complete"
Serialized version of a real message:
"{\"player_stats\":\"{\\\"assist\\\":0,\\\"deaths\\\":0,\\\"kills\\\":0,\\\"team_index\\\":2}\",\"round_attr\":\"{\\\"max_player_count\\\":4,\\\"rdur\\\":0,\\\"round\\\":1,\\\"team_player_count\\\":{\\\"team_1\\\":1,\\\"team_2\\\":0},\\\"team_score\\\":0}\",\"custom\":\"{\\\"armor\\\":\\\"armor_pickup_lv2\\\",\\\"balance\\\":550,\\\"helmet\\\":\\\"helmet_pickup_lv2\\\",\\\"misc\\\":[{\\\"count\\\":48,\\\"item_id\\\":\\\"shotgun\\\"},{\\\"count\\\":120,\\\"item_id\\\":\\\"bullet\\\"},{\\\"count\\\":2,\\\"item_id\\\":\\\"health_pickup_combo_small\\\"},{\\\"count\\\":2,\\\"item_id\\\":\\\"health_pickup_health_small\\\"}],\\\"weapon_1\\\":\\\"mp_weapon_semipistol\\\",\\\"weapon_2\\\":\\\"mp_weapon_shotgun_pistol\\\"}\",\"gdur\":\"0\"}"
To complicate even more
Create a model class is not an option because this json is completely dynamic
Flatting the dictionary is not possible because the json may have duplicated key names, but under different hierarchy
I cant request to change the Kafka message
What I am trying to do
The end user will define rules that I need to check if I find a match. For instance, a rule could be reward.xp == 200 or reward.loot.rarity == high or status == complete. These rules will be defined by the user so it cant be hardcoded, however I can decide with data structure to use to save them. So for each Kafka message, I have to iterate through that dictionary and try to find a match with the rules.
What I have tried
I ve tried JsonConvert.Deserialize to object, dynamic, ExpandoObject and none could handle the nested json hierarchy. They just got the 1st level correct. Same result with JObject.Parse as well.

Parse the JSON using whatever parser you like (I used Newtonsoft.Json).
Then recursively visit the hierarchy and copy each property to a flat list using the full path to each property value as a key. You can then iterate that flat list.
Edit: Comment requested supporting arrays, so this version does.
https://dotnetfiddle.net/6ykHT0
using System;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
string json = #"{
'reward': {
'xp': '200',
'gp': '150',
'loot': {
'item': 'sword',
'rarity': 'low',
'blah': {
'socks': 5
}
},
'arrayofint': [1,2,3,4],
'arrayofobj': [
{
'foo': 'bar',
'stuff': ['omg!', 'what?!']
},
{
'foo': 'baz',
'stuff': ['a', 'b']
}
],
'arrayofarray': [
[1,2,3],
[4,5,6]
],
'arrayofheterogenousjunk': [
'a',
2,
{ 'objprop': 1 },
['staahp!']
]
},
'achievement': 'win_match'
}";
JObject data = JObject.Parse(json);
IList<string> nodes = flattenJSON(data);
Console.WriteLine(string.Join(Environment.NewLine, nodes));
}
private static IList<string> flattenJSON(JToken token)
{
return _flattenJSON(token, new List<string>());
}
private static IList<string> _flattenJSON(JToken token, List<string> path)
{
var output = new List<string>();
if (token.Type == JTokenType.Object)
{
// Output the object's child properties
output.AddRange(token.Children().SelectMany(x => _flattenJSON(x, path)));
}
else if (token.Type == JTokenType.Array)
{
// Output each array element
var arrayIndex = 0;
foreach (var child in token.Children())
{
// Append the array index to the end of the last path segment - e.g. someProperty[n]
var newPath = new List<string>(path);
newPath[newPath.Count - 1] += "[" + arrayIndex++ + "]";
output.AddRange(_flattenJSON(child, newPath));
}
}
else if (token.Type == JTokenType.Property)
{
var prop = token as JProperty;
// Insert the property name into the path
output.AddRange(_flattenJSON(prop.Value, new List<string>(path) { prop.Name }));
}
else
{
// Join the path segments delimited with periods, followed by the literal value
output.Add(string.Join(".", path) + " = " + token.ToString());
}
return output;
}
}
Output:
reward.xp = 200
reward.gp = 150
reward.loot.item = sword
reward.loot.rarity = low
reward.loot.blah.socks = 5
reward.arrayofint[0] = 1
reward.arrayofint[1] = 2
reward.arrayofint[2] = 3
reward.arrayofint[3] = 4
reward.arrayofobj[0].foo = bar
reward.arrayofobj[0].stuff[0] = omg!
reward.arrayofobj[0].stuff[1] = what?!
reward.arrayofobj[1].foo = baz
reward.arrayofobj[1].stuff[0] = a
reward.arrayofobj[1].stuff[1] = b
reward.arrayofarray[0][0] = 1
reward.arrayofarray[0][1] = 2
reward.arrayofarray[0][2] = 3
reward.arrayofarray[1][0] = 4
reward.arrayofarray[1][1] = 5
reward.arrayofarray[1][2] = 6
reward.arrayofheterogenousjunk[0] = a
reward.arrayofheterogenousjunk[1] = 2
reward.arrayofheterogenousjunk[2].objprop = 1
reward.arrayofheterogenousjunk[3][0] = staahp!
achievement = win_match
PREVIOUS VERSION (NO ARRAY SUPPORT)
This doesn't properly support arrays - it will output the contents of a property that is an array as the raw JSON - i.e. it won't traverse into the array.
https://dotnetfiddle.net/yZbwul
public static void Main()
{
string json = #"{
'reward': {
'xp': '200',
'gp': '150',
'loot': {
'item': 'sword',
'rarity': 'low',
'blah': {
'socks': 5
}
}
},
'achievement': 'win_match'
}";
JObject data = JObject.Parse(json);
IList<string> nodes = flattenJSON(data, new List<string>());
Console.WriteLine(string.Join(Environment.NewLine, nodes));
}
private static IList<string> flattenJSON(JObject obj, IList<string> path)
{
var output = new List<string>();
foreach (var prop in obj.Properties())
{
if (prop.Value.Type == JTokenType.Object)
{
output.AddRange(flattenJSON(prop.Value as JObject, new List<string>(path){prop.Name}));
}
else
{
var s = string.Join(".", new List<string>(path) { prop.Name }) + " = " + prop.Value.ToString();
output.Add(s);
}
}
return output;
}
Output:
reward.xp = 200
reward.gp = 150
reward.loot.item = sword
reward.loot.rarity = low
reward.loot.blah.socks = 5
achievement = win_match

Related

Pick only one record from a JSON array in C#

I'm trying to extract a record from a JSON array but it doesn't seem to work.
Here my code :
DataTable table = ConvertJsonToDatatable(responseBody);
System.Windows.Forms.MessageBox.Show(table.Columns[1].ToString(), "transformation");
The MessageBox isn't showing. I have checked responseBody and the variable isn't empty at all.
Here the structure of this variable (and the JSON array rear)
{
"data":
[
[
1651217520000,
1.0562,
1.0562,
1.056,
1.0561,
0,
0
],
[
1651217580000,
1.0561,
1.0563,
1.0561,
1.0561,
0,
0
]
],
"events": null
}
public static DataTable ConvertJsonToDatatable(string jsonString)
{
var jsonLinq = JObject.Parse(jsonString);
// Find the first array using Linq
var linqArray = jsonLinq.Descendants().Where(x => x is JArray).First();
var jsonArray = new JArray();
foreach (JObject row in linqArray.Children<JObject>())
{
var createRow = new JObject();
foreach (JProperty column in row.Properties())
{
// Only include JValue types
if (column.Value is JValue)
{
createRow.Add(column.Name, column.Value);
}
}
jsonArray.Add(createRow);
}
return JsonConvert.DeserializeObject<DataTable>(jsonArray.ToString());
}
Does anyone have an idea of how to extract/pick one value from this array (which is a string in my code) ?
Have a nice week end everyone and thanks in advance
you have to fix table creating code
public static DataTable ConvertJsonToDatatable(string jsonString)
{
var jsonLinq = JObject.Parse(jsonString);
// Find the first array using Linq
var linqArray = jsonLinq.Descendants().Where(x => x is JArray).First();
//or maybe this would be enough
var linqArray = JObject.Parse(jsonString)["data"];
var jsonArray = new JArray();
foreach (var row in (JArray)linqArray)
{
var createdRow = new JObject();
var i = 0;
foreach (var item in row)
{
i++;
createdRow.Add("col" + i.ToString(), (string)item);
}
jsonArray.Add(createdRow);
}
return jsonArray.ToObject<DataTable>();
}
how to use
DataTable table = ConvertJsonToDatatable(responseBody);
string val = table.Rows[0].Field<string>("col2");
System.Windows.Forms.MessageBox.Show(val, "transformation");
i probably would be marked negative, but i try to explain how it looks like inside. i made example to show tow to get back list of arrays it might visualize for you.
void Main()
{
string json = "{\"data\":[[1651217520000,1.0562,1.0562,1.056,1.0561,0,0],[1651217580000,1.0561,1.0563,1.0561,1.0561,0,0]],\"events\":null}";
var obj = JObject.Parse(json);
foreach (JToken token in obj.FindTokens("data"))
{
foreach (JArray row in JArray.Parse(token.ToString()))
{
row.Dump();
row[0].Dump("first element");
}
}
}
public static class JsonExtensions
{
public static List<JToken> FindTokens(this JToken containerToken, string name)
{
List<JToken> matches = new List<JToken>();
FindTokens(containerToken, name, matches);
return matches;
}
private static void FindTokens(JToken containerToken, string name, List<JToken> matches)
{
if (containerToken.Type == JTokenType.Object)
{
foreach (JProperty child in containerToken.Children<JProperty>())
{
if (child.Name == name)
{
matches.Add(child.Value);
}
FindTokens(child.Value, name, matches);
}
}
else if (containerToken.Type == JTokenType.Array)
{
foreach (JToken child in containerToken.Children())
{
FindTokens(child, name, matches);
}
}
}
}
result would be an array of jarray
so you can build you DataTable rows
.Dump() is a left over from linqpad. Good tool. Same as console.write

Set value in JObject using JsonPath [duplicate]

There is a large JSON file (about a thousand lines). The task is to update existing JProperties, or add new JProperties in a specific location in the structure. The location of the new texts are based on the JToken.Path property. For example, this is the start of the JSON:
"JonSnow": {
"Direwolf": {
"Name": "Ghost",
"Color": "White",
}
}
"DanaerysTargaryen": {
"Dragons": {
"Dragon1": {
"Name": "Drogon",
}
}
"Hair": {
"Color": "White"
}
}
Now the JSON must be updated using a given list of JToken paths and the corresponding values.
The first possibility is, the JProperty corresponding to the path might already exist, in which case the value needs to be updated. I am already successfully implementing this with JToken.Replace().
The second possibility is, the JProperty does not exist yet and needs to be added. For example, I need to add "DanaerysTargaryen.Dragons.Dragon1.Color" with the value "Black".
I know I can use the JSON.Net Add() method, but to use this only the final child token of the path can be missing from the JSON. For example, I can use
JObject ObjToUpdate= JObject.Parse(jsonText);
JObject Dragon = ObjToUpdate["DanaerysTargaryen"]["Dragons"]["Dragon1"] as JObject;
Dragon.Add("Color", "Black"));
But what about if I need to add "JonSnow.Weapon.Type" with the value "Longsword"? Because "Weapon" does not exist yet as a JProperty, and it needs to be added along with "Type" : "Longsword". With each path, it is unknown how much of the path already exists in the JSON. How can this be parameterised?
// from outside source: Dictionary<string, string> PathBasedDict
// key: Jtoken.Path (example: "JonSnow.Weapon.Type")
// value: new text to be added (example: "Longsword")
foreach(KeyValuePair entry in PathBasedDict)
{
string path = entry.Key;
string newText = entry.Value;
if (ObjToUpdate.SelectToken(path) != null)
{ ObjToUpdate.SelectToken(path).Replace(newText); }
else AddToJson(path, newText);
}
What should AddToJson() look like? Iterating through the entire path and checking each possible JProperty to see if it exists, and then adding the rest underneath, seems very cumbersome. Is there a better way to do this? Any Json.NET tricks I am unaware of? I am not even sure how the iteration could be parameterised.
Based on first approach from Heretic Monkey's answer, here is an extension method:
public static class JObjectExtensions
{
/// <summary>
/// Replaces value based on path. New object tokens are created for missing parts of the given path.
/// </summary>
/// <param name="self">Instance to update</param>
/// <param name="path">Dot delimited path of the new value. E.g. 'foo.bar'</param>
/// <param name="value">Value to set.</param>
public static void ReplaceNested(this JObject self, string path, JToken value)
{
if (self is null)
throw new ArgumentNullException(nameof(self));
if (string.IsNullOrEmpty(path))
throw new ArgumentException("Path cannot be null or empty", nameof(path));
var pathParts = path.Split('.');
JToken currentNode = self;
for (int i = 0; i < pathParts.Length; i++)
{
var pathPart = pathParts[i];
var isLast = i == pathParts.Length - 1;
var partNode = currentNode.SelectToken(pathPart);
if (partNode is null)
{
var nodeToAdd = isLast ? value : new JObject();
((JObject)currentNode).Add(pathPart, nodeToAdd);
currentNode = currentNode.SelectToken(pathPart);
}
else
{
currentNode = partNode;
if (isLast)
currentNode.Replace(value);
}
}
}
}
There are a few ways of going about this. Here are two of them.
To go along with your existing code, split the path by '.', then iterate over them. If the path is not there, create it with Add. Otherwise, if we're on the last part of the path, just add the value.
var json = JObject.Parse(#"{""DanaerysTargaryen"":{""Dragons"":{""Dragon1"":{""Name"": ""Drogon""}},""Hair"": {""Color"": ""White""}}}");
var toAdd = "DanaerysTargaryen.Dragons.Dragon1.Color";
var valueToAdd = "Black";
var pathParts = toAdd.Split('.');
JToken node = json;
for (int i = 0; i < pathParts.Length; i++)
{
var pathPart = pathParts[i];
var partNode = node.SelectToken(pathPart);
if (partNode == null && i < pathParts.Length - 1)
{
((JObject)node).Add(pathPart, new JObject());
partNode = node.SelectToken(pathPart);
}
else if (partNode == null && i == pathParts.Length - 1)
{
((JObject)node).Add(pathPart, valueToAdd);
partNode = node.SelectToken(pathPart);
}
node = partNode;
}
Console.WriteLine(json.ToString());
(Example on dotnetfiddle.net)
Otherwise, you could create a separate JObject that represents the node(s) you want to add, then merge them.
var json = JObject.Parse(#"{""DanaerysTargaryen"":{""Dragons"":{""Dragon1"":{""Name"": ""Drogon""}},""Hair"": {""Color"": ""White""}}}");
var toMerge = #"{""DanaerysTargaryen"":{""Dragons"":{""Dragon1"":{""Color"":""Black""}}}}";
var jsonToMerge = JObject.Parse(toMerge);
json.Merge(jsonToMerge);
Console.WriteLine(json.ToString());
(Example on dotnetfiddle.net)

How to add a new JProperty to a JSON based on path?

There is a large JSON file (about a thousand lines). The task is to update existing JProperties, or add new JProperties in a specific location in the structure. The location of the new texts are based on the JToken.Path property. For example, this is the start of the JSON:
"JonSnow": {
"Direwolf": {
"Name": "Ghost",
"Color": "White",
}
}
"DanaerysTargaryen": {
"Dragons": {
"Dragon1": {
"Name": "Drogon",
}
}
"Hair": {
"Color": "White"
}
}
Now the JSON must be updated using a given list of JToken paths and the corresponding values.
The first possibility is, the JProperty corresponding to the path might already exist, in which case the value needs to be updated. I am already successfully implementing this with JToken.Replace().
The second possibility is, the JProperty does not exist yet and needs to be added. For example, I need to add "DanaerysTargaryen.Dragons.Dragon1.Color" with the value "Black".
I know I can use the JSON.Net Add() method, but to use this only the final child token of the path can be missing from the JSON. For example, I can use
JObject ObjToUpdate= JObject.Parse(jsonText);
JObject Dragon = ObjToUpdate["DanaerysTargaryen"]["Dragons"]["Dragon1"] as JObject;
Dragon.Add("Color", "Black"));
But what about if I need to add "JonSnow.Weapon.Type" with the value "Longsword"? Because "Weapon" does not exist yet as a JProperty, and it needs to be added along with "Type" : "Longsword". With each path, it is unknown how much of the path already exists in the JSON. How can this be parameterised?
// from outside source: Dictionary<string, string> PathBasedDict
// key: Jtoken.Path (example: "JonSnow.Weapon.Type")
// value: new text to be added (example: "Longsword")
foreach(KeyValuePair entry in PathBasedDict)
{
string path = entry.Key;
string newText = entry.Value;
if (ObjToUpdate.SelectToken(path) != null)
{ ObjToUpdate.SelectToken(path).Replace(newText); }
else AddToJson(path, newText);
}
What should AddToJson() look like? Iterating through the entire path and checking each possible JProperty to see if it exists, and then adding the rest underneath, seems very cumbersome. Is there a better way to do this? Any Json.NET tricks I am unaware of? I am not even sure how the iteration could be parameterised.
Based on first approach from Heretic Monkey's answer, here is an extension method:
public static class JObjectExtensions
{
/// <summary>
/// Replaces value based on path. New object tokens are created for missing parts of the given path.
/// </summary>
/// <param name="self">Instance to update</param>
/// <param name="path">Dot delimited path of the new value. E.g. 'foo.bar'</param>
/// <param name="value">Value to set.</param>
public static void ReplaceNested(this JObject self, string path, JToken value)
{
if (self is null)
throw new ArgumentNullException(nameof(self));
if (string.IsNullOrEmpty(path))
throw new ArgumentException("Path cannot be null or empty", nameof(path));
var pathParts = path.Split('.');
JToken currentNode = self;
for (int i = 0; i < pathParts.Length; i++)
{
var pathPart = pathParts[i];
var isLast = i == pathParts.Length - 1;
var partNode = currentNode.SelectToken(pathPart);
if (partNode is null)
{
var nodeToAdd = isLast ? value : new JObject();
((JObject)currentNode).Add(pathPart, nodeToAdd);
currentNode = currentNode.SelectToken(pathPart);
}
else
{
currentNode = partNode;
if (isLast)
currentNode.Replace(value);
}
}
}
}
There are a few ways of going about this. Here are two of them.
To go along with your existing code, split the path by '.', then iterate over them. If the path is not there, create it with Add. Otherwise, if we're on the last part of the path, just add the value.
var json = JObject.Parse(#"{""DanaerysTargaryen"":{""Dragons"":{""Dragon1"":{""Name"": ""Drogon""}},""Hair"": {""Color"": ""White""}}}");
var toAdd = "DanaerysTargaryen.Dragons.Dragon1.Color";
var valueToAdd = "Black";
var pathParts = toAdd.Split('.');
JToken node = json;
for (int i = 0; i < pathParts.Length; i++)
{
var pathPart = pathParts[i];
var partNode = node.SelectToken(pathPart);
if (partNode == null && i < pathParts.Length - 1)
{
((JObject)node).Add(pathPart, new JObject());
partNode = node.SelectToken(pathPart);
}
else if (partNode == null && i == pathParts.Length - 1)
{
((JObject)node).Add(pathPart, valueToAdd);
partNode = node.SelectToken(pathPart);
}
node = partNode;
}
Console.WriteLine(json.ToString());
(Example on dotnetfiddle.net)
Otherwise, you could create a separate JObject that represents the node(s) you want to add, then merge them.
var json = JObject.Parse(#"{""DanaerysTargaryen"":{""Dragons"":{""Dragon1"":{""Name"": ""Drogon""}},""Hair"": {""Color"": ""White""}}}");
var toMerge = #"{""DanaerysTargaryen"":{""Dragons"":{""Dragon1"":{""Color"":""Black""}}}}";
var jsonToMerge = JObject.Parse(toMerge);
json.Merge(jsonToMerge);
Console.WriteLine(json.ToString());
(Example on dotnetfiddle.net)

Build a Property List from a JSON Object c#

I want to build the property list including property path of a json object.
I don't know the structure of the json or the keys that might be present. I'm after the keys at all levels (not the values of those keys).
{
"Primitive_1": "T1",
"Object_L1": {
"Object_L2": {
"Object_L3": {
"Object_L4": {
"Object_L5": {
"Object_L6": {
"Array_L7": [
{
"asdasdas": "SampleText1",
"WIDTH": "Width2"
},
{
"gh45gdfg": "SampleText2",
"WIDTH": "Width"
}
],
"12836hasvdkl": "SampleText3",
"WIDTH": "Width"
}
}
},
"712bedfabsmdo98": "SampleText4",
"WIDTH": "Width"
}
},
"ALIAS_ID": 1
},
"Primitive_2": "T2",
"Primitive_3": "T3",
"Primitive_4": "T4"
}
Desired output:
.Primitive_1 .Object_L1.Object_L2.Object_L3.Object_L4.Object_L5.Object_L6.Array_L7.0.asdasdas
.Object_L1.Object_L2.Object_L3.Object_L4.Object_L5.Object_L6.Array_L7.0.WIDTH
.Object_L1.Object_L2.Object_L3.Object_L4.Object_L5.Object_L6.Array_L7.1.gh45gdfg
.Object_L1.Object_L2.Object_L3.Object_L4.Object_L5.Object_L6.Array_L7.1.WIDTH
.Object_L1.Object_L2.Object_L3.Object_L4.Object_L5.Object_L6.12836hasvdkl
.Object_L1.Object_L2.Object_L3.Object_L4.Object_L5.Object_L6.WIDTH
.Object_L1.Object_L2.Object_L3.712bedfabsmdo98
.Object_L1.Object_L2.Object_L3.WIDTH
.Object_L1.ALIAS_ID
.Primitive_2
.Primitive_3
.Primitive_4
Having looked around I've gotten as far as the root nodes of the object. See fiddle (https://dotnetfiddle.net/wIl1Qw)
This seems to be relatively simple in JS (http://jsfiddle.net/alteraki/bt3zc1wt/) I've already reviewed several responses and I can't find a response in c# that solves this problem without knowing the keys in use (which I don't know)
Any help would be much appreciated.
Tree traversal algorithms are almost always recursive in nature.
As such, the following function does what you want:
private static IEnumerable<string> GetMembers(JToken jToken)
{
var members = new List<string>();
if (jToken is JObject)
{
var jObject = (JObject)jToken;
foreach (var prop in jObject.Properties())
{
if (prop.Value is JValue)
{
members.Add(prop.Name);
}
else
{
members.AddRange(GetMembers(prop.Value).Select(member => prop.Name + "." + member));
}
}
}
else if (jToken is JArray)
{
var jArray = (JArray)jToken;
for (var i = 0; i < jArray.Count; i++)
{
var token = jArray[i];
members.AddRange(GetMembers(token).Select(member => i + "." + member));
}
}
return members;
}
An example of the code running is available here.

How do I process arrays within an array?

I have an array of arrays of arrays as JSON, a sample included below where
F1 = Feature #1
P1 = Point #1
X / Y = Coordinates
so F1P1X is the X-value of point #1 of feature #1.
[
[
[F1P1X,F1P1Y,null],
[F1PnX,F1PnY,null]
],
[
[F2P1X,F2P1Y,null],
[F2PnX,F2PnY,null]
],
[
[FnP1X,FnP1Y,null],
[FnPnX,FnPnY,null]
]
]
Here is the code I use to get the above JSON from a file:
string json = File.ReadAllText("ABC.json");
JObject obj = JObject.Parse(json);
JToken token = obj.SelectToken("$.features[?(#.name == 'X')]['XY']");
var paths = JToken.Parse(token.ToString()).SelectToken("XYZ");
Next, I need to build strings using the various arrays. How do I get the second-level array (the feature) so I can process its innermost arrays (points on the features)? The end will be List<string> where each string is a feature (second-level array in the JSON) and the innermost array are the points that make the feature. I can handle the string manipulation but first I need to get the arrays out of the JSON.
Good choice is Json.NET nuget package for work with JSON. I have create test method for you.
//Read your json file
string json = File.ReadAllText("ABC.json");
//deserialize
F1P1X[][][] yourArrayOfArraysOfArrays = JsonConvert.DeserializeObject<F1P1X[][][]>(json).ToList();
public class F1P1X
{
public string Feature { get; set; }
public string Point { get; set; }
public string Coordinates { get; set; }
}
public static void Test()
{
F1P1X[] test1Array = new[]
{
new F1P1X
{
Feature = "F1",
Point = "P1",
Coordinates = "X1"
},
new F1P1X
{
Feature = "F2",
Point = "P2",
Coordinates = "X2"
},
};
F1P1X[] test2Array = new[]
{
new F1P1X
{
Feature = "F3",
Point = "P3",
Coordinates = "X3"
},
new F1P1X
{
Feature = "F4",
Point = "P4",
Coordinates = "X4"
},
};
F1P1X[][] test = {test1Array, test2Array};
F1P1X[][] test2 = { test1Array, test2Array };
F1P1X[][][] top = {test, test2};
//array of arrays of arrays as JSON
string json = JsonConvert.SerializeObject(top);
List<F1P1X[][]> arrays = JsonConvert.DeserializeObject<F1P1X[][][]>(json).ToList();
foreach (F1P1X[][] item in arrays)
{
foreach (F1P1X[] f1P1X in item)
{
foreach (F1P1X p1X in f1P1X)
{
//do some magic
}
}
}
// or use linq
var result = arrays.SelectMany(x => x.SelectMany(y => y.Where(z => z.Coordinates == "X1")));
}
This linq statement returns list of features
List<string> result = arrays.SelectMany(x => x.SelectMany(y => y.Select(z => z.Feature))).ToList();

Categories