Get specific data from a JSON - c#

Suppose there is a JSON structure like below
{
"v": "2021",
"Outeritems": [
{
"items": [
{
"c": "r",
"KeyOne": "DataOne",
"KeyTwo": "DataTwo",
"items": [
{
"c": "r",
"KeyOne": "DataThree",
"KeyTwo": "DataFour",
"v": "F",
"h": "N",
"l": "N:"
},
{
"c": "r",
"KeyOne": "DataFive",
"KeyTwo": "DataSix",
"v": "T"
}
]
}
]
}
]
}
How can I read all KeyOne and its corresponding KeyTwo(line below KeyOne) using linq or some method. They may be nested in any of items array. We need to get all such properties as a dictionary or key value pair like that. Thanks for help.

Well instead commenting out, lets build an aprox answer.
Actually the better aproach is deserialize the JSON to a class with only the relevant properties, instead trying to use all the JSON structure.
Like:
private class Item
{
[JsonProperty("KeyOne")]
public string KeyOne { get; set; }
[JsonProperty("KeyTwo")]
public string KeyTwo { get; set; }
[JsonProperty("items")]
public List<Item> Items { get; set; }
}
private class Outeritem
{
[JsonProperty("items")]
public List<Item> Items { get; set; }
}
private class Root
{
[JsonProperty("Outeritems")]
public List<Outeritem> Outeritems { get; set; }
}
Then deserialize like:
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
Then for transverse the tree you can use a recursive aproach (just because a JSON string is a rather finite structure, not a good aproach in ALL cases)
List<string> KeyOneValues = new List<string>();
List<string> KeyTwoValues = new List<string>();
trasverseNode(List<Item> item)
{
if (item.KeyOne != null) KeyOneValues.Add(item.KeyOne);
if (item.KeyTwo != null) KeyTwoValues.Add(item.KeyTwo);
foreach (Item child in item.Items)
{
trasverseNode(child); //<-- recursive
}
}

Related

Getting data in Json.Net c#

I want to get data from json file correctly. The json data file I modeled for this is as follows:
{
"Free title 1":[
{
"Subject": "a1",
"Relation": "a2"
},
{
"Subject": "b1",
"Relation": "b2"
}
],
"Another free title":[
{
"Subject": "z1",
"Relation": "z2"
},
{
"Subject": "y1",
"Relation": "y2"
}
],
"Unordered title":[
{
"Subject": "x1",
"Relation": "x2"
},
{
"Subject": "w1",
"Relation": "w2"
}
]
}
This is how I create an object class:
public class _Infos_
{
public List<_Info_> Infos { get; set; }
}
public class _Info_
{
public string Subject { get; set; }
public string Relation { get; set; }
}
And finally I'm trying to get the data in a method like this:
var js = JsonConvert.DeserializeObject<_Infos_>(File.ReadAllText("__FILE_PATH__"));
foreach (var j in js.Infos)
{
MessageBox.Show(j.Subject);
}
I get the error that js is empty. Here I want to get Free title 1, Another free title and Unordered title in a list. Of course, these titles will be constantly changing. Afterwards, I want to get the Subject and Relation data under these titles. But I have no idea how to get it.
This data structure is a dictionary of collections of _Info_s. You need to deserialize it to Dictionary<string, List<_Info_>>.
Here are System.Text.Json and Json.net examples:
var d = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, List<_Info_>>>(json);
var d2 = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, List<_Info_>>>(json);
Your class definition is a little wrong.
You can use online tools "json to c#" to generate the correct classes.
like this one: https://json2csharp.com
Your "root" of your json for example does not contain an array in your json. The property "Free title 1":[..] is an array, so your root needs a property with the name FreeTitle1 and it has to be an array/list.
public class Root
{
[JsonProperty("Free title 1")]
public List<TitleInfo> FreeTitle1 { get; set; }
[JsonProperty("Another free title")]
public List<TitleInfo> AnotherFreeTitle { get; set; }
[JsonProperty("Unordered title")]
public List<TitleInfo> UnorderedTitle { get; set; }
}
public class TitleInfo
{
public string Subject { get; set; }
public string Relation { get; set; }
}
If your object members have dynamic names, you can also manually deserialize the object, e.g. using the general type JObject. E.g.
JObject obj = JObject.Parse(File.ReadAllText("__FILE_PATH__"));
JObject implements IEnumerable<KeyValuePair<string, JToken>> over which you can iterate.
Each member will then have JToken Value, which is a JArray in this case, which you can cast to a List of your type.
foreach (var groups in obj)
{
var infos = groups.Value.ToObject<List<_Info_>>();
// .. loop over infos
}

Convert Dynamic Json to Something more Concrete

How can I deserialize the JSON below to a C# array or something more manageable.
{
"data": [
{
"PropertyName": [
{
"Key1": "test",
"Key2": "afafa"
},
{
"Key1": "test",
"Key2": "afafa"
}
],
"PropertyName2": [
{
"Key1": "test",
"Key2": "afafa"
},
{
"Key1": "test",
"Key2": "afafa"
}
]
}
]
}
It comes in as a dynamic parameter like this:
public IActionResult SAve([FromBody] dynamic mapping)
I normally would make this a concrete class but "PropertyName" will change to different names, so I need something flexible. The contents of it can be concrete as it is just two properties.
I am thinking that it could be like a dictionary.
Dictionary<string, ConcreteClass>()
I just don't know how to get it into that form.
Edit.
I have gone ahead and did the suggestion but it does not work
{{
"data": [
{
"propertyName": [
{
"key1": 1,
"key2": "1"
},
{
"key1": 2,
"key2": "2"
}
]
}
]
}}
I tried to convert like this
var ddd = JsonConvert.DeserializeObject<List<MappingDto>>(mapping.data.ToString());
this makes an empty object in the array. If I don't have it wrapped in a collection then I get a different error
public class MappingDto
{
public List<Dictionary<string, List<Item>>> Items { get; set; }
}
public class Items
{
public string Key1{ get; set; }
public string Key2{ get; set; }
}
For this JSON, a concrete class structure that handles the dynamic property names as you described would look like this:
public class MappingDto
{
public List<Dictionary<string, List<Item>>> Data { get; set; }
}
public class Item
{
public string Key1 { get; set; }
public string Key2 { get; set; }
}
Be sure to update your method signature to use the new class instead of dynamic:
public IActionResult SAve([FromBody] MappingDto mapping)
You can then access the data like this (for example):
foreach (var dict in mapping.Data)
{
foreach (var kvp in dict)
{
Debug.WriteLine(kvp.Key);
foreach (var item in kvp.Value)
{
Debug.WriteLine(" Key1: " + item.Key1);
Debug.WriteLine(" Key2: " + item.Key2);
}
}
}
Fiddle: https://dotnetfiddle.net/OGylPh

JSon.Net deserialize custom class

I want to deserialize a json object to a custom class. The class could look like this:
public class CommunicationMessage {
public string Key { get; set; }
public string Value { get; set; }
public List<CommunicationMessage> Childs { get; set; }
}
And the json I want to deserialize looks like this:
{
"Skills": [{
"Skill": [{
"SkillID": "1",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "2",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "3",
"ParticipantID": "7",
"CanDo": "False"
}]
}]
}
And this is the code I am using to deserialize the json:
private void ReadRecursive(JToken token, ref CommunicationMessage root) {
if (token is JProperty) {
CommunicationMessage msg = new CommunicationMessage();
if (token.First is JValue) {
msg.Key = ((JProperty)token).Name;
msg.Value = (string)((JProperty)token).Value;
} else {
msg.Key = ((JProperty)token).Name;
foreach (JToken child in token.Children()) {
ReadRecursive(child, ref msg);
}
}
root.Childs.Add(msg);
} else {
foreach (JToken child in token.Children()) {
ReadRecursive(child, ref root);
}
}
}
I am expecting to get this hirarchy:
Skills
Skill
SkillID:1
ParticipantID:7
CanDo:true
Skill
SkillID:2
ParticipantID:7
CanDo:true
Skill
SkillID:3
ParticipantID:7
CanDo:false
But I am getting this:
Skills
Skill
SkillID:1
ParticipantID:7
CanDo:
SkillID:2
ParticipantID:7
CanDo:true
SkillID:3
ParticipantID:7
CanDo:false
I can't find the lines where my failure is, so maybe anyone can help me here.
Thanks!!
Your code seems to do its job quite ok (although there are simpler ways to achieve your goal). The problematic part is the JSON it self. It's organized in two arrays.
So your code puts out the Skills-array (which has one element) and the Skill-array which holds the actual the 3 skills you're expecting.
{
"Skills": [{ // array -> note the [
"Skill": [{ // array -> note the [
Hence one way to solve this would be to edit the JSON (if this is possible):
{
"Skills": [{
"SkillID": "1",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "2",
"ParticipantID": "7",
"CanDo": "True"
}, {
"SkillID": "3",
"ParticipantID": "7",
"CanDo": "False"
}]
}
Use Newtonsoft Json.NET.
output message = JsonConvert.DeserializeObject<CommunicationMessage>(json);
(where json is the JSON string.)
I used this page - json2csharp - to create classes that match the JSON you posted:
public class Skill2
{
public string SkillID { get; set; }
public string ParticipantID { get; set; }
public string CanDo { get; set; }
}
public class Skill
{
public List<Skill2> Skill { get; set; }
}
public class CommunicationMessage
{
public List<Skill> Skills { get; set; }
}
The class names are autogenerated. It always names the root object RootObject. But you can change it to CommunicationMessage (I did.)
If you want the class to have different property names that don't match the JSON you can do that with attributes.
public class Skill2
{
[JsonProperty["Key"]
public string SkillID { get; set; }
[JsonProperty["Value"]
public string ParticipantID { get; set; }
public string CanDo { get; set; }
}
Using a DataContractJsonSerializerfrom System.Runtime.Serializationwould make the deserialization easier:
Stream data = File.OpenRead(#"data.json");
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(CommunicationMessage));
CommunicationMessage message = (CommunicationMessage)serializer.ReadObject(data);
But you also need a class like this:
[DataContract]
class CommunicationMessage
{
[DataContract]
class SkillsData
{
[DataContract]
internal class SkillData
{
[DataMember(Name = "SkillID")]
internal object SkillID;
[DataMember(Name = "ParticipantID")]
internal object ParticipantID;
[DataMember(Name = "CanDo")]
internal object CanDo;
}
[DataMember(Name = "Skill")]
internal SkillData[] Skill;
}
[DataMember(Name = "Skills")]
SkillsData[] Skills;
}
Above you have the class SkillData, which holds the data of each skill. So if you take the array Skill, you have the wanted hirarchy.
You could just check for when you are at the right level/object type using logic inside your recursive method.
void ReadRecursive(JToken token, ref CommunicationMessage root)
{
var p = token as JProperty;
if (p != null && p.Name == "Skill")
{
foreach (JArray child in p.Children())
{
foreach (JObject skill in child.Children())
{
// Create/add a Skill message instance for current Skill (JObject)
var skillMsg = new CommunicationMessage { Key = p.Name };
// Populate Childs for current skill instance
skillMsg.Childs = new List<CommunicationMessage>();
foreach (JProperty skillProp in skill.Children())
{
skillMsg.Childs.Add(new CommunicationMessage
{
Key = skillProp.Name,
Value = (string)skillProp.Value
});
}
root.Childs.Add(skillMsg);
}
}
}
// Recurse
foreach (JToken child in token.Children())
ReadRecursive(child, ref root);
}

How to deserialize this JSON array

The JSON is coming in like this (pseudo code):
[{one-off intro object}, [{object},{object},{object}]]
So it's an array where the first thing in the array is an object I'm not interested in and the second is another array full of the objects I actually want to deserialize.
How can I do this with JSON.NET?
You can use Json.Net's LINQ-to-JSON API to do the job.
For sake of example, let's assume your JSON looks like this:
[
{
"blah": "nothing interesting here"
},
[
{
"id": 1,
"name": "foo",
"desc": "description of foo"
},
{
"id": 2,
"name": "bar",
"desc": "blurb about bar"
},
{
"id": 3,
"name": "baz",
"desc": "buzz about baz"
}
]
]
First, define a class to hold the items from the inner array that you're interested in.
public class Item
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("desc")]
public string Description { get; set; }
}
Now, all you need to do is parse the JSON to a JArray, then get the child array from that and use ToObject() to convert it to a list of items.
JArray ja = JArray.Parse(json);
List<Item> list = ja[1].ToObject<List<Item>>();
From there, you can use the list of items as you normally would.
Fiddle: https://dotnetfiddle.net/CaFzux
You can get to the second set of objects either via strongly typed casting or dynamically, here is an example of doing it dynamically:
dynamic jsonArray = JArray.Parse(json);
dynamic targetJsonObjects = jsonArray[1];
Have you tried just simple model like this?
public class RootObject
{
public object IntroObject { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public string WhatEverPropertyYouNeed{ get; set; }
}

C# List<List<T>>

I have a class with the following property: Education.cs
Apologize for the perhaps basic question
public List<List<Education>>data { get; set; }
public class Education
{
public From school { get; set; }
public From year { get; set; }
public string type { get; set; }
}
This is the class I have defined for deserializing json string
From is another .cs file
public string id { get; set; }
public string name { get; set; }
Here is my json string
education": [
{
"school": {
"id": "107751089258341",
"name": "JNTU, Kakinada, India"
},
"year": {
"id": "132393000129123",
"name": "2001"
},
"type": "College"
},
{
"school": {
"id": "103710319677602",
"name": "University of Houston"
},
"year": {
"id": "113125125403208",
"name": "2004"
},
"type": "Graduate School"
}
]
Can someone tell me how to access the members of Education(school, year)? It could be a piece of cake for you.
In my aspx.cs,
I have to write a foreach or any other to access my variables, school.name, year.name
Will have to work this access of class members into my aspx.cs
url= "https://graph.facebook.com/me?fields=education&access_token=" + oAuth.Token;
json = oAuth.WebRequest(oAuthFacebook.Method.GET, url, String.Empty);
List<Education>??? = js.Deserialize<List<??>(json)
Thanks
Smitha
You need two foreach loops inside of eachother; one for each level of List<>.
#Slaks solution should work for you. Though I believe your data is better represented as List<Education> (or better still, IEnumerable<Education>) and what you may want to do is to Flatten it out.
It would be better to flatten it out at the source, to make sure your code is cleaner at other places.
If you are on .NET 3.5 you can do it like
var flattenData = data.SelectMany(x => x);
If you are on pre .NET 3.5 / C# 3.0, you can do it like this
//Your original code block
{
IEnumerable<Education> flattenData = FlattenMyList(data);
//use flatten data normally
}
IEnumerable<T> FlattenMyList<T> (List<List<T> data){
foreach(List<T> innerList in data){
foreach(T item in innerList){
yield return item;
}
}
yield break;
}

Categories