Create multiple objects from JSON file - c#

I have a JSON file, that has many JSON objects:
[
"DIEM":
{
"Name":["A"],
"InRul":[]
},
"DOAN":
{
"Name":["A","B"],
"InRul":[]
},
"TAMGIAC":
{
"Name":["A","B","C"],
"InRul":[]
},
"TAMGIACVUONG":
{
"Name":["A","B","C"],
"InRul":[]
}
]
and, I have a class in C#:
class Content
{
public string Name;
public List<string> InRul;
}
How can I convert the JSON file above to objects in C#?
DIEM.Name //print Array [A]
DOAN.Name //print Array [A,B]
Thank so much!

Related

Created Nested JSON array from JSON array

I am pretty new to JSON and C# and have created an Azure Function that ties back to Snowflake which requires a very specific type of JSON response. I would like assistance if any in turning a JSON response I'm getting to a slightly different formatted response.
{
"access_token": "access token value here" , "user": "user_val"
}
to looking like
{
"data":
[
[ 0, { "access_token" : "access token value here", "user" : "user_val" } ]
]
}
I need create a nested array with "data" as the parent and a row number response starting at 0.
Using Json.NET:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string json = #"{
""access_token"": ""access token value here"" , ""user"": ""user_val""
}";
Access a = JsonConvert.DeserializeObject<Access>(json);
var accessCollection = new AccessCollection
{
Data = new List<Access> { a }
};
json = JsonConvert.SerializeObject(accessCollection, Formatting.Indented);
Console.WriteLine(json);
}
}
public class Access
{
[JsonProperty("access_token")]
public string AccessToken
{
get;
set;
}
[JsonProperty("user")]
public string User
{
get;
set;
}
}
public class AccessCollection
{
[JsonProperty("data")]
public List<Access> Data
{
get;
set;
}
}
In addition, I consider the inner array is not usual because the data type are int and object. In general, they should be of same type. Because of that, I use a single dimensional array instead.
Please modify the codes according to situation.
.NET Fiddle

Parse JSON Objects with unique strings as parents using JSON.Net

Let's say I have this example JSON:
"Test": {
"KIf42N7OJIke57Dj6dkh": {
"name": "test 1"
},
"xsQMe4WWMu19qdULspve": {
"name": "test 2"
}
}
I want to parse this into an Array of a custom class I have, which will be exampled below:
class Class1 {
public string Name { get; set; }
Class1(string name) {
Name = name;
}
}
How can I parse this using Json.NET's JObject.Parse?
You can achieve your goal with JPath query like this :
var myArray = JObject
.Parse(json)
.SelectTokens("$.Test..name")
.Values<string>()
.Select(s => new Class1(s))
.ToArray();
But probably not the best way to do it.
I personnaly prefere to create classes to represent the json structure and then apply transformations.
void Main()
{
var json = #"{""Test"": {
""KIf42N7OJIke57Dj6dkh"": {
""name"": ""test 1""
},
""xsQMe4WWMu19qdULspve"": {
""name"": ""test 2""
}
}
}";
var root = JsonConvert.DeserializeObject<Root>(json);
var array = root.Test.Select(i => i.Value).ToArray();
array.Dump();
}
public class Root
{
public Dictionary<string, Class1> Test { get; set; }
}
public class Class1
{
public string Name { get; set; }
public Class1(string name)
{
Name = name;
}
}
To begin with, your Json is missing starting/closing braces. The Json needs to have wrapping braces around the Test value.
{
'Test':
{
'KIf42N7OJIke57Dj6dkh': {'name': 'test 1'},
'xsQMe4WWMu19qdULspve': {'name': 'test 2'}
}
}
If you are missing it in the original Json, you could wrap the current input Json as following.
var correctedJson = $"{{{inputJsonString}}}";
If you want to parse the Json Objects to Array of Class1 without creating additional concrete data structures and using JPath Queries, you could use Anonymous Types for the purpose using the DeserializeAnonymousType Method proved by Json.Net. For example,
var sampleObject = new {Test = new Dictionary<string,Class1>()};
var data = JsonConvert.DeserializeAnonymousType(correctedJson,sampleObject);
var result = data.Test.Select(x=>x.Value).ToArray();
You could also achieve it using JPath Query or creating Concrete Data Structures as #Kalten as described in his answer.

Deserialize nested objects with JsonUtility

I would like to deserialize my json files holding information about levels. Given this example .json file called 1.json
{
"name": "Level One",
"map": [
[{
"groundTexture": "grass",
"cellType": "empty",
"masterField": null,
"worldObjects": [{
"worldObjectType": "player",
"rotation": 90
}]
},{
"groundTexture": "grass",
"cellType": "obstacle",
"masterField": null,
"worldObjects": [{
"worldObjectType": "tree",
"rotation": 0
}]
}],[{
"groundTexture": "grass",
"cellType": "campFire",
"masterField": null,
"worldObjects": [{
"worldObjectType": "campfire",
"rotation": 270
}]
},{
"groundTexture": "grass",
"cellType": "related",
"masterField": {
"x": 1,
"y": 0
},
"worldObjects": []
}]
]
}
I would like to convert the data from that file to a class object holding all the data needed to create a level during runtime. I created a reader which only reads the file content
public class LevelReader : MonoBehaviour
{
private string levelBasePath;
private void Awake()
{
levelBasePath = $"{Application.dataPath}/ExternalFiles/Levels";
}
public string GetFileContent(string levelName)
{
string file = $"{levelName}.json";
string filePath = Path.Combine(levelBasePath, file);
return File.ReadAllText(filePath);
}
}
and a mapper which maps the json string to a LevelInfo object.
public class LevelMapper : MonoBehaviour
{
private void Start()
{
// DEBUGGING TEST
LevelReader levelReader = GetComponent<LevelReader>();
string levelContent = levelReader.GetFileContent("1");
LevelInfo levelInfo = MapFileContentToLevelInfo(levelContent);
Debug.Log(levelInfo.cells);
}
public LevelInfo MapFileContentToLevelInfo(string fileContent)
{
return JsonUtility.FromJson<LevelInfo>(fileContent);
}
}
The following structs just help to create an object containg all the level data:
[Serializable]
public struct LevelInfo
{
public string name;
public LevelCell[][] cells;
}
[Serializable]
public struct LevelCell
{
public string groundTexture;
public string cellType;
public Vector2? masterField;
public LevelWorldObject[] worldObjects;
}
[Serializable]
public struct LevelWorldObject
{
public string worldObjectType;
public int rotation;
}
When starting the application the mapper runs and loops through the data object. Unfortunately the cells are null. How can I deserialize the file correctly?
In LevelInfo structure you have field "cells" but in Json - "map". They must be the same.
JsonUtility can't serialize/deserialize multidimensional arrays.
https://answers.unity.com/questions/1322769/parsing-nested-arrays-with-jsonutility.html
https://docs.unity3d.com/Manual/script-Serialization.html
I believe you can change your data structures or use another serializer.

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.

Categories

Resources