Deserialize objects nested within an array [duplicate] - c#

This question already has answers here:
Parse JSON in C#
(7 answers)
Closed 4 years ago.
I am struggling to deserialize the following JSON string that I am receiving from an API:
{
"appointment_types": [
{
"id": 279148,
"max_attendees": 1,
"name": "Follow up",
"billable_item": {
"links": {
"self": "https://api.cliniko.com/v1/billable_items/485545"
}
},
"practitioners": {
"links": {
"self": "https://api.cliniko.com/v1/appointment_types/279148/practitioners"
}
}
},
{
"id": 279149,
"max_attendees": 1,
"name": "Assessment",
"billable_item": {
"links": {
"self": "https://api.cliniko.com/v1/billable_items/490437"
}
},
"practitioners": {
"links": {
"self": "https://api.cliniko.com/v1/appointment_types/279149/practitioners"
}
}
}
],
"total_entries": 17,
"links": {
"self": "https://api.cliniko.com/v1/appointment_types?page=1"
}
}
I have searched but I couldn't find anything that would work for the above.
Any pointers that may get me on the right track would be greatly appreciated.

This seems to work fine for me just using dynamic...
dynamic d = JObject.Parse(json);
var totalNumber = d.total_entries.ToString();
var theId = d.appointment_types[0].id.ToString();
What have you tried?

I would create c# classes for the structure and then use Newtonsoft Json.NET for deserializion. (It is fast and already in c# but you have to add the reference.)
Here is my code:
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("demo.json"); //Your json here
RequestResult requestResult = Newtonsoft.Json.JsonConvert.DeserializeObject<RequestResult>(json); //There is your result
Console.WriteLine("Done!");
Console.ReadLine();
}
}
class RequestResult
{
public AppointmentType[] appointment_types;
public int total_entries;
public Link links;
}
class Practitioners
{
public Link links;
}
class BillableItem
{
public Link links;
}
class Link
{
public string self;
}
class AppointmentType
{
public int id;
public int max_attendees;
public string name;
public BillableItem billable_item;
public Practitioners practitioners;
}
Then you have the result as a c# object and things like intellisense and code completion do work.

Related

How do I get info from an object with an array of objects in a json for Unity?

I have a JSON file setup as such
{
"cards": [
{
"id": "sand_bags",
"type": "Structure",
"name": "Sand Bags",
"values": [
{
"civilian": 1,
"fiend": -1
}
],
"effectTexts": [
{
"civilian": "Add +1 to your BUNKER.",
"fiend": "Send any CIVILIAN'S +1 STRUCTURE to the SCRAPYARD."
}
],
"flavorTexts": [
{
"civilian": "They're just heavy bags with sand. Not much else to say, but they'll slow down an attack from a fiend. Good luck, you'll need it!",
"fiend": "You've spotted a pretty bad STRUCTURE in this BUNKER. Time to do some damage."
}
],
"staysOnField": [
{
"civilian": true,
"fiend": false
}
],
"amountInDeck": 5
}
]
}
I also have a Cards script
[Serializable]
public class Cards
{
public Card[] cards;
}
[Serializable]
public class Card
{
public string id;
public string type;
public string name;
public int amountInDeck;
}
public class Values
{
public int civilian;
public int fiend;
}
I then have a CardEffects script that I'm using for my functions.
public class CardEffects : MonoBehaviour
{
public TextAsset jsonFile;
public Values values;
void Start()
{
Cards cardsInJson = JsonUtility.FromJson<Cards>(jsonFile.text);
foreach (Card card in cardsInJson.cards)
{
Debug.Log("Card name: " + card.name + " with " + values.civilian + " in the deck.");
}
}
}
I have searched all over trying to figure out how to even get the array of objects of "values". I got this far and the value printed is always 0 regardless of the information in "values" in the JSON. If I make the class Serializable, I'm able to change the values and it works but I want the values to be whatever they were declared as in the JSON. Is there a better way to do this?
Please keep in mind I'm new to C# and Unity. I usually code in JS in which using JSON files are no big deal for me and thought it was the best way to go.
Your json and your classes doesn't match. Not only that your json isn't even valid Json. Below I will give you your correct json and class.
{
"cards": [
{
"id": "sand_bags",
"type": "Structure",
"name": "Sand Bags",
"values": [
{
"civilian": 1,
"fiend": -1
}
],
"effectTexts": [
{
"civilian": "Add +1 to your BUNKER.",
"fiend": "Send any CIVILIAN'S +1 STRUCTURE to the SCRAPYARD."
}
],
"flavorTexts": [
{
"civilian": "They're just heavy bags with sand. Not much else to say, but they'll slow down an attack from a fiend. Good luck, you'll need it!",
"fiend": "You've spotted a pretty bad STRUCTURE in this BUNKER. Time to do some damage."
}
],
"staysOnField": [
{
"civilian": true,
"fiend": false
}
],
"amountInDeck": 5
}
] // <---- This was missing
}
For that Json this is how your card class will have to look like:
public Card
{
public string id { get; set; }
public string type { get; set; }
public string name { get; set; }
public Values[] values { get; set; }
public Values[] effectTexts { get; set; }
public Values[] staysOnField { get; set; }
public int amountInDeck { get; set; }
}
And your Values class have to look like this:
public class Values
{
public object civilian;
public object fiend;
}
I suggest MiniJson.
You can just copy paste the script to your project and you are ready to go.
The then can call Json.Deserialize(string json) passing your string in. For the case of an array you can do for example:
IList myJsonElements = (IList)Json.Deserialize(string json);
Find working snippet:
using System;
using Newtonsoft.Json;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args) {
string myJson = "{\"cards\": [{\"id\": \"sand_bags\",\"type\": \"Structure\",\"name\": \"Sand Bags\",\"values\": [{\"civilian\": 1,\"fiend\": -1}],\"effectTexts\": [{\"civilian\": \"Add +1 to your BUNKER.\",\"fiend\": \"Send any CIVILIAN'S +1 STRUCTURE to the SCRAPYARD.\"}],\"flavorTexts\": [{\"civilian\": \"They're just heavy bags with sand. Not much else to say, but they'll slow down an attack from a fiend. Good luck, you'll need it!\",\"fiend\":\"You've spotted a pretty bad STRUCTURE in this BUNKER. Time to do some damage.\"}],\"staysOnField\": [{\"civilian\": true,\"fiend\": false}],\"amountInDeck\": 5}]}";
var myJsonElements = MiniJSON.Json.Deserialize(myJson);
Console.WriteLine(myJsonElements.ToString());
string json = JsonConvert.SerializeObject(myJsonElements, Formatting.Indented);
Console.WriteLine(json);
Console.ReadLine();
}
}
}

Dynamically retrieve variable and argument values for NativeActivity

When I run the below code (C#) as a custom activity (compiled .dll is added to a nuget package and triggered in a UiPath sequence with some user defined variables/arguments. I am able to retrieve the name of the variable and it's type, but I cannot find the proper syntax to retrieve the value (I just want to convert it to a String, no need to do anything fancy). I can access some of the properties, so i know i am close. I have done my best to read the docs, but in this instance, it may be a little two abstract for me. I have gone through many interations and scoured as much of the internet as I can, but I cannot seem to figure it out.
using Newtonsoft.Json.Linq;
using System;
using System.Activities;
using System.Activities.Hosting;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
namespace AutoLog
{
public sealed class GetRootActivity : NativeActivity
{
public OutArgument<string> variables { get; set; }
protected override void Execute(NativeActivityContext context)
{
this.variables.Set((ActivityContext)context, Library.getLocalVariables(context));
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
metadata.AddDefaultExtensionProvider<GetRootActivity.WorkflowInstanceInfo>((Func<GetRootActivity.WorkflowInstanceInfo>)(() => new GetRootActivity.WorkflowInstanceInfo()));
}
public class Library
{
public static string getLocalVariables(NativeActivityContext context)
{
var properties = context.DataContext.GetProperties();
JArray variables = new JArray();
foreach(PropertyDescriptor p in properties)
{
JObject variable = new JObject();
variable["name"] = p.Name;
variable["type"] = p.PropertyType.ToString();
string string_value = "";
try
{
var myValue = context.DataContext.GetType().GetProperty(p.Name).GetValue(context.DataContext, null);
string_value = myValue.ToString();
}
catch(Exception e)
{
}
variable["value"] = string_value;
variables.Add(variable);
}
return variables.ToString();
}
}
}
}
Below is an example of the JSON it generates, as you can see, the "value" field is empty
[
{
"name": "a",
"type": "System.String",
"value": ""
},
{
"name": "b",
"type": "System.Boolean",
"value": ""
},
{
"name": "c",
"type": "System.Int32",
"value": ""
},
{
"name": "test",
"type": "System.String",
"value": ""
},
{
"name": "f",
"type": "System.String",
"value": ""
}
]
var myValue = context.DataContext.GetType().GetProperty(p.Name).GetValue(context.DataContext, null);
string_value = myValue.ToString();
can be changed to
string_value = p.GetValue(context.DataContext) as String;
I had previously tried this approach but got trying to make the cast dynamic, and apparently I had never tried the simpler solution.

Deserialize JSON value without name

How can I deserialize a string in C# that only have values and no name. It looks like this: The problem is that this stream of string does not have name and uses array.
{
"result": {
"14400": [
[
1502985600,
262.18,
262.18,
257,
257,
1096.0131
],
[
1503000000,
257,
261.33,
254.8,
257,
1130.5897
]
],
"14405": [
[
1503014400,
258.03,
261.5,
257.01,
257.01,
520.7805
],
[
1503028800,
258,
260.98,
252.4,
259.56,
298.5658
],
]
]
}
}
Just create a class like
public class Root
{
public Dictionary<int,List<List<double>>> Result { get; set; }
}
and deserialize as
var res = JsonConvert.DeserializeObject<Root>(json);
I see it's an array, you could create a method to parse the class out of given JArray.
The Jason data
public void methpod()
{
string json ="Your jason value "
var factory = new Factory();
var suggest = factory.Create(json);
Console.WriteLine(suggest);
}
Make a class as suggested :
public class Factory
{
public Evan Create(string json)
{
var array = JArray.Parse(json);
string search = array[0].ToString();
string[] terms = array[1].ToArray().Select(item => item.ToString()).ToArray();
return new Evan{Search = search, Terms = terms};
}
}
and another
public class Evan
{
public string Search { get; set; }
public IEnumerable<string> Terms { get; set; }
public override string ToString()
{
return string.Format("Search={0},Terms=[{1}]",
Search, string.Join(",", Terms));
}
}
Tip
If you have JSON that you want to deserialize, and you don't have the class to deserialize it into, Visual Studio 2019 can automatically generate the class you need:
Copy the JSON that you need to deserialize.
Create a class file and delete the template code.
Choose Edit > Paste Special > Paste JSON as Classes.
The result is a class that you can use for your deserialization target

How to deserialise a JSON object where the object structure is not known

Part of my code serializes file paths of a machine into JSON in the below format. I am struggling to take this JSON and put the file paths back together again. I am using Newtonsoft JSON lib; I find it's excellent for building JSON. As you can see, my JSON has nested objects.
The JSON I have:
{
".": {
"proc": {
"15": {
"task": {
"15": {
"exe": {},
"mounts": {
"list_of_files": [
"mounts.xml"
]
},
"mountinfo": {
"list_of_files": [
"mountinfo.xml"
]
},
"clear_refs": {
"list_of_files": [
"clear_ref.xml"
]
}
}
}
},
"14": {
"loginuid": {
"list_of_files": [
"loginuid.xml"
]
},
"sessionid": {
"list_of_files": [
"sessionid.xml"
]
},
"coredump_filter": {
"list_of_files": [
"coredump_filter.xml"
]
},
"io": {
"list_of_files": [
"io.xml"
]
}
}
}
}
}
The array I want to generate from this.
string[] dirArray = {
"./proc/15/task/15/exe",
"./proc/15/task/15/mounts/mounts.xml",
"./proc/15/task/15/mountinfo/mountinfo.xml",
"./proc/15/task/15/clear_refs/clear_ref.xml",
"./proc/14/loginuid/loginuid.xml",
"./proc/14/sessionid/sessionid.xml",
"./proc/14/coredump_filter/coredump_filter.xml",
"./proc/14/io/io.xml"
}
My efforts so far-- I deserialised the JSON into a dynamic variable but I'm not sure how to handle two issues:
My JSON format is unknown, I don't know how deep the objects go, how can I handle this?
How do I work with dynamic variables when they are defined at run-time?
EDIT
Sorry, my original JSON format was wrong, so it doesn't work with the answer provided by user12864. I'm getting an error: Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.
Here is a fiddle showing where I'm at so far.
#user12864 has the right idea in his answer, but the code needs to be adjusted to account for the fact that each directory can have an array of files rather a single "file" object (you really should have mentioned that in your question originally). Here is an updated method to handle that:
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
Full demo:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
string json = #"
{
""."": {
""proc"": {
""15"": {
""task"": {
""15"": {
""exe"": {},
""mounts"": {
""list_of_files"": [
""mounts.xml""
]
},
""mountinfo"": {
""list_of_files"": [
""mountinfo.xml""
]
},
""clear_refs"": {
""list_of_files"": [
""clear_ref.xml""
]
}
}
}
},
""14"": {
""loginuid"": {
""list_of_files"": [
""loginuid.xml""
]
},
""sessionid"": {
""list_of_files"": [
""sessionid.xml""
]
},
""coredump_filter"": {
""list_of_files"": [
""coredump_filter.xml""
]
},
""io"": {
""list_of_files"": [
""io.xml""
]
}
}
}
}
}";
JObject jo = JObject.Parse(json);
foreach (string path in CreateFileList(jo))
{
Console.WriteLine(path);
}
}
private static List<string> CreateFileList(JObject jo)
{
List<string> ret = new List<string>();
AddToFileList(jo, ret, "");
return ret;
}
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
}
Output:
./proc/15/task/15/exe
./proc/15/task/15/mounts/mounts.xml
./proc/15/task/15/mountinfo/mountinfo.xml
./proc/15/task/15/clear_refs/clear_ref.xml
./proc/14/loginuid/loginuid.xml
./proc/14/sessionid/sessionid.xml
./proc/14/coredump_filter/coredump_filter.xml
./proc/14/io/io.xml
Fiddle: https://dotnetfiddle.net/r8CkI2
This should give exactly what you're looking for; just create a JObject with JObject.Parse and pass it to CreateFileList. It won't handle malformed JSON in any nice way.
static List<string> CreateFileList(JObject j)
{
List<string> ret = new List<string>();
AddToFileList(j, ret, "");
return ret;
}
static void AddToFileList(JObject j, List<string> dest, string prefix)
{
if (prefix.Length != 0)
prefix = prefix + '/';
foreach (var kvp in j)
{
var jnext = (JObject)kvp.Value;
if (kvp.Key == "file")
dest.Add(prefix + (string)jnext["name"]);
else
AddToFileList(jnext, dest, prefix + kvp.Key);
}
}
Fiddle at https://dotnetfiddle.net/dQQ4tI
Update:
Here is a revised answer, after you clarified your requirement of:
The JavaScript Object Notation is built on the server, edited by user through a hierarchical tree interface component. That can be crawled incredibly easy.
So in essence your utilizing a component, in which your hoping to build simple JavaScript Object Notation derived from the component. Your User Interface will be unknown, so I'll make some presumptions.
Build our Object:
public class XmlPath
{
public string Location { get; set; }
}
The XmlPath will represent our object. Which will be basic auto property.
Add Content to our Object:
private List<XmlPath> AddXmlPath(List<string> location)
{
List<XmlPath> content = new List<XmlPath>();
foreach(string item in location)
content.Add(new XmlPath() { Location = item });
return content;
}
This will be incredibly simple method, it will take a large List<string> of your user data and add them to your XmlPath object.
Remove content from our Object:
private List<XmlPath> RemoveXmlPath(List<XmlPath> root, string location)
{
root.Remove(new XmlPath() { Location = location });
return root;
}
Those two methods truly don't need to be, I'm just demonstrating and showing how you could. Plus it will outline the intentions a bit easier for you to implement. Please note this is incredibly crude approach.
Serialize / Deserialize Our Object to JavaScript Objection Notation:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var xmlPath = AddXmlPath(List<string> location);
var result = serializer.Serialize(xmlPath);
var deserialize = serializer.Deserialize(List<XmlPath>>(result);
Our content is exposed now through a basic loop:
foreach(XmlPath item in deserialize)
{
// Exposed Model via 'item.Location'
}
You'll simply need to correlate this core functionality to your implementation. The approach is crude, quite rudimentary, definitely will need to be improved on for production. However this should get you started with:
Serialize data on the server.
Deserialize server data.
Manipulating the object.
Hope this is better for you.

How to read this type ofJson [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a Json data please suggest me how to read this type of Json.
{"Questions": [
{
"Question": "Who was the Chola King who brought Ganga from North to South?",
"CorrectAnswer": 1,
"Answers": [
{
"Answer": "Raja Raja Chola"
},
{
"Answer": "Rajendra Chola"
},
{
"Answer": "Parantaka"
},
{
"Answer": "Mahendra"
}
]
},
{
"Question": "The writ of 'Habeas Corpus' is issued in the event of:",
"CorrectAnswer": 2 ,
"Answers": [
{
"Answer": "Loss of Property"
},
{
"Answer": "Refund of Excess Taxes"
},
{
"Answer": "Wrongful Police Detention"
},
{
"Answer": "Violation of the Freedom of Speech"
}
]}
]}
Newtonsoft.Json is my favorite library to manipulate JSON
Your code should be something like:
EDITED
public class AnswerObj{
public string Answer{get;set;}
}
public class QuestionObj{
public string Question {get;set;}
public int CorrectAnswer {get;set;}
public List<AnswerObj> Answers {get;set;}
}
public class QuestionsRepository
{
public List<QuestionObj> Questions {get;set;}
}
//Here is the code for reading your JSON
string json = "Your_JSON_COMES_HERE as a string"
QuestionsRepository questions = JsonConvert.DeserializeObject<QuestionsRepository>(json);
You can use builtin .NET, DataContractJsonSerializer class, which can be used to Serialize and Deserialize json strings. (MSDN Link)
Here is a complete tutorial in MSDN: (How to: Serialize and Deserialize JSON data)
I prefer to use at least frameworks as possible. Look at my code.
For the given object structure:
public class QuestionsRepository
{
public List<QuestionObj> Questions;
}
public class QuestionObj
{
public string Question;
public UInt16 CorrectAnswer;
public AnswerObj[] Answers;
}
public class AnswerObj
{
public string Answer;
}
Declare trivial simplest wrapper:
public static class JsonUtils
{
class JsonSerializer<T>
{
static DataContractJsonSerializer xs = new DataContractJsonSerializer(typeof(T));
public static object DeserializeObject(string serializedData, Encoding encoding)
{
byte[] data = encoding.GetBytes(serializedData);
MemoryStream sr = new MemoryStream(data);
return xs.ReadObject(sr);
}
public static string SerializeObject(T obj, Encoding encoding)
{
MemoryStream ms = new MemoryStream();
xs.WriteObject(ms, obj);
byte[] data = ms.ToArray();
return encoding.GetString(data);
}
}
public static T DeserializeObject<T>(this string serializedData)
{
return (T)JsonSerializer<T>.DeserializeObject(serializedData, Encoding.Default);
}
public static string SerializeObject<T>(this T obj)
{
return JsonSerializer<T>.SerializeObject(obj, Encoding.Default);
}
}
Sample:
class Program
{
static void Main()
{
try
{
string json = "{\"Questions\": [{ \"Question\": \"Who was the Chola King who brought Ganga from North to South?\", \"CorrectAnswer\": 1, \"Answers\": [ { \"Answer\": \"Raja Raja Chola\" }, { \"Answer\": \"Rajendra Chola\" }, { \"Answer\": \"Parantaka\" }, { \"Answer\": \"Mahendra\" } ] }, { \"Question\": \"The writ of 'Habeas Corpus' is issued in the event of:\", \"CorrectAnswer\": 2 , \"Answers\": [{ \"Answer\": \"Loss of Property\" }, { \"Answer\": \"Refund of Excess Taxes\" }, { \"Answer\": \"Wrongful Police Detention\" }, { \"Answer\": \"Violation of the Freedom of Speech\" }] }]}}";
QuestionsRepository newRepository = json.DeserializeObject<QuestionsRepository>();
for (int i = 0; i < newRepository.Questions.Count; i++)
{
Console.WriteLine("{0}", newRepository.Questions[i].Question);
int count = 1;
foreach (var answer in newRepository.Questions[i].Answers)
{
Console.WriteLine("\t{0}) {1} ({2})", count, answer.Answer, newRepository.Questions[i].CorrectAnswer == count ? "+" : "-");
count++;
}
}
}
catch (SerializationException serEx)
{
Console.WriteLine(serEx.Message);
Console.WriteLine(serEx.StackTrace);
}
}
}
P.S.: Classes must be top-level enities with default constructor available (visible, accessible classes for data serializer) to be uses in DataContractJsonSerializer

Categories

Resources