Json Searching Data Structures - c#

This is my Data Structure and I'm trying to access it with simpleJason, through unity/c#, I have accidentally gotten the right data here and there, and otherwise gotten completely empty arrays, I'd like to know if my JSON file is improperly setup for my data structure, or if the parser is somehow falling though, or not properly matching what I'm looking for.
JSON File:
{
"categories": [
{
"name" : "entertainment",
"projects": [
{
"name": "Awards",
"description": "Awards Shows",
"credits": [
"Lead Engineer - Dave Jones",
"VFX Supervisor - John Adrian",
"CG Supervisor - Evan Klein"
],
"meta": [
"awards",
"show",
"stars",
"red carpet"
],
"assets": [
{
"name": "Screen Actors Guild Awards",
"filename": "SAG_Awards.mp4",
"icon": "sag.png",
"stereo": false,
"meta": [
"Screen",
"Actors",
"Guild"
]
},
{
"name": "No Awards",
"filename": "No_SAG_Awards.mp4",
"icon": "no_sag.png",
"stereo": false,
"meta": [
"Screen",
"Actors",
"Guild"
]
},
{
"name": "None Awds",
"filename": "None_SAG_Awards.mp4",
"icon": "none_sag.png",
"stereo": false,
"meta": [
"Screen",
"Actors",
"Guild"
]
}
]
}
]
}
]
}
This is the struct :
private struct jsonAsset {
public string category;
public string project;
public string description;
public string[] credits;
public string[] meta;
public string asset;
public FileInfo file;
public FileInfo icon;
public bool stereo;
public bool overUnder;
};
This is the function:
jsonAsset LoadSceneDataFromJSON(FileInfo jsonFile)
{
jsonAsset asset = new jsonAsset();
Debug.Log("Processing : " + jsonFile);
// Parse File for Data
var N = JSON.Parse(File.ReadAllText(jsonFile.FullName));
var cat_arr = N["categories"].AsArray;
asset.category = N["categories"]["name"].Value;
Debug.Log(N["categories"]["projects"]["assets"]["filename"].Value);
foreach (JSONNode n in cat_arr)
{
asset.project = n["name"].Value;
// Credits
var proj_credits = n["credits"].AsArray;
foreach (JSONNode pc in proj_credits)
{
asset.credits[asset.credits.Length] = pc["credits"].Value;
}
// Project Meta
var proj_meta = n["meta"].AsArray;
foreach (JSONNode pm in proj_meta)
{
asset.meta[asset.meta.Length] = pm["meta"].Value;
}
// Project Array
var proj_arr = n["projects"].AsArray;
foreach (JSONNode nn in proj_arr)
{
var asset_arr = nn["assets"].AsArray;
asset.asset = nn["assets"]["name"].Value;
foreach (JSONNode nnn in asset_arr)
{
asset.asset = nnn["name"].Value;
asset.file = new FileInfo(m_dir + nnn["filename"].Value);
asset.icon = new FileInfo(m_dir + nnn["icon"].Value);
var asset_meta = nnn["meta"].AsArray;
foreach (JSONNode am in asset_meta)
{
asset.meta[asset.meta.Length] = am.Value;
}
}
}
}
return asset;
}

You are treating projects as an object instead of an array.
I dont know what JSON library you are using to give you guidance, but something like this will probably work:
N["categories"]["projects"][0]["assets"]["filename"].Value

Related

How can I search a JSON file in C# by a key value, and then obtain a subsequent key + value?

I have 3 JSON files that all contain the same data structure, however different data.
The structure for all 3 files is as follows:
{
"TokenId": "0",
"rank": "2804"
},
{
"TokenId": "1",
"rank": "977"
},
{
"TokenId": "2",
"rank": "4085"
}
I am trying to create a new JSON file from these 3 files that has the following structure, and yes, they all have the same tokenID values, but slightly different rank values:
{
"TokenId": "0",
"File1Rank": "2804",
"File2Rank": "2802",
"File3Rank": "2809"
},
{
"TokenId": "1",
"File1Rank": "977",
"File2Rank": "983",
"File3Rank": "999"
},
{
"TokenId": "2",
"File1Rank": "4085",
"File2Rank": "4089",
"File3Rank": "4100"
}
How can I search by the tokenId value in each file to obtain the rank value? I can iterate through each valuea in each file to get both values, but I am struggling to create or update the new JSON correctly. The logic I feel I need is if the TokenId is equal to a certain value, then add the rank key/value, but I have not been able to find the answer on how I can do this.
You can use the newtonsoft json library to parse and update the json files.
If your source file structure is:
{
"Tokens": [
{
"TokenId": "0",
"rank": "2804"
},
{
"TokenId": "1",
"rank": "977"
},
{
"TokenId": "2",
"rank": "4085"
}
]
}
Pseudo code:
using Newtonsoft.Json
using Newtonsoft.Json.Linq
void Main()
{
dynamic objFinal = JObject.Parse("{ 'Tokens':[] }");
JArray finalArray = (JArray)objFinal["Tokens"];
DirectoryInfo dir = new DirectoryInfo(#"D:\Projects\JsonFiles\");
foreach(var file in dir.GetFiles("*.json"))
{
dynamic objJson = JObject.Parse(File.ReadAllText(file.FullName));
JArray tokens = (JArray)objJson["Tokens"];
foreach(JToken token in tokens)
{
JToken searchResult = finalArray.Where(t=> Convert.ToString(t["TokenId"])==Convert.ToString(token["TokenId"])).FirstOrDefault();
if(searchResult==null)
{
//push new tokenid
JArray newFileRanks = new JArray();
newFileRanks.Add(token["rank"]);
dynamic newToken = new JObject();
newToken["TokenId"] = token["TokenId"];
newToken["fileRanks"] = newFileRanks;
finalArray.Add(newToken);
}
else
{
//append to fileRanks
JArray existingFileRanks = (JArray)searchResult["fileRanks"];
dynamic fileRankExists = existingFileRanks.Where(t=> Convert.ToString(t)==Convert.ToString(token["rank"])).FirstOrDefault();
if(fileRankExists==null)
{
existingFileRanks.Add(token["rank"]);
}
}
}
}
Console.Write(JsonConvert.SerializeObject(objFinal));
}
Final output:
{
"Tokens": [
{
"TokenId": "0",
"fileRanks": [ "2804", "2801" ]
},
{
"TokenId": "1",
"fileRanks": [ "977", "972" ]
},
{
"TokenId": "2",
"fileRanks": [ "4085", "4083" ]
}
]
}

how to work with nested json object in c#

api return json which is nested and i dont know to retrieve data from it and map it to my model. i want to retrieve the data from nested but not sure how to do this with index and value. Thanks in Advance.
public class MikesExcelModel
{
//public int id;
//public object AuthorizingManagerId;
public string Name;
//public DateTime UpdateDate;
public string Phone;
public string Email;
}
public class MikesExcelResults
{
public List<MikesExcelModel> value = new List<MikesExcelModel>();
}
public List<MikesExcelModel> GetExcel()
{
using (HttpClient client = new HttpClient())
{
addToken(client);
var result = client.GetAsync("https://graph.microsoft.com/beta/sites/ucfdev.sharepoint.com,4c319763-130d-4ee1-bc1f-72543da0a847,8a2f59f4-9d56-4aec-be21-33d0347293d1/drives/b!Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m/items/01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH/workbook/worksheets('sheet1')/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows").Result;
if (result.IsSuccessStatusCode)
{
var responseContent = result.Content;
// by calling .Result you are synchronously reading the result
string responseString = responseContent.ReadAsStringAsync().Result;
JavaScriptSerializer serialiser = new JavaScriptSerializer();
// dynamic apiResult = serialiser.DeserializeObject(responseString);
return Utilities.DeserializeObject<MikesExcelResults>(result.Content.ReadAsStringAsync().Result).value;
}
else
throw new Exception("Couldn't get excel datas.");
}
}
}
Data return by api looks like this:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets('sheet1')/tables('%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D')/rows",
"value": [
{
"#odata.id": "/sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets(%27%7B00000000-0001-0000-0000-000000000000%7D%27)/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows/itemAt(index=0)",
"index": 0,
"values": [
[
"Mike Callahan",
"407-266-1431",
"MTC#ucf.edu"
]
]
},
{
"#odata.id": "/sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets(%27%7B00000000-0001-0000-0000-000000000000%7D%27)/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows/itemAt(index=1)",
"index": 1,
"values": [
[
"Michael Callahan",
"407-823-3455",
"mtcallah#ucf.edu"
]
]
},
{
"#odata.id": "/sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets(%27%7B00000000-0001-0000-0000-000000000000%7D%27)/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows/itemAt(index=2)",
"index": 2,
"values": [
[
"cvcfcv",
"zVCCvc",
"cvvvvb"
]
]
}
]
}
Maybe traditional way to extract JSON data with Newtonsoft.Json library.
Convert jsonData to JObject (via JObject.Parse).
Get first-level value.
Get second-level values.
Flatten second-level values.
From
[[["Mike Callahan", "407-266-1431", "MTC#ucf.edu"], ...]]
To
[["Mike Callahan", "407-266-1431", "MTC#ucf.edu"], ...]
Convert flattenChildrenValues to List<MikesExcelModel>.
Add List<MikesExcelModel> to results.value
using System;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
var jsonData = #"{
""#odata.context"": ""https://graph.microsoft.com/beta/$metadata#sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets('sheet1')/tables('%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D')/rows"",
""value"": [
{
""#odata.id"": ""/sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets(%27%7B00000000-0001-0000-0000-000000000000%7D%27)/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows/itemAt(index=0)"",
""index"": 0,
""values"": [
[
""Mike Callahan"",
""407-266-1431"",
""MTC#ucf.edu""
]
]
},
{
""#odata.id"": ""/sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets(%27%7B00000000-0001-0000-0000-000000000000%7D%27)/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows/itemAt(index=1)"",
""index"": 1,
""values"": [
[
""Michael Callahan"",
""407-823-3455"",
""mtcallah#ucf.edu""
]
]
},
{
""#odata.id"": ""/sites('ucfdev.sharepoint.com%2C4c319763-130d-4ee1-bc1f-72543da0a847%2C8a2f59f4-9d56-4aec-be21-33d0347293d1')/drives('b%21Y5cxTA0T4U68H3JUPaCoR_RZL4pWnexKviEz0DRyk9HjXtfo70gjRbH706GdwO5m')/items('01HA4SXKSESD3RW3UYPNCZ2OHQAEWWDTKH')/workbook/worksheets(%27%7B00000000-0001-0000-0000-000000000000%7D%27)/tables(%27%7B079215E2-A6D7-4CC2-AB1E-9AC38F36D1CC%7D%27)/rows/itemAt(index=2)"",
""index"": 2,
""values"": [
[
""cvcfcv"",
""zVCCvc"",
""cvvvvb""
]
]
}
]
}";
var jsonObj = JObject.Parse(jsonData);
// Get first-level value
JArray jsonValue = jsonObj["value"] as JArray;
// Get second-level values
var childrenValues = jsonValue.Children<JObject>()["values"];
// Flatten second-level values
var flattenChildrenValues = childrenValues.Values<JArray>() as IEnumerable<JArray>;
// Read flattenChildrenValues to List<MikesExcelModel>
List<MikesExcelModel> excelModels = flattenChildrenValues
.Select(x => new MikesExcelModel
{
Name = x[0].ToString(),
Phone = x[1].ToString(),
Email = x[2].ToString()
})
.ToList();
// Add List<MikesExcelModel> to results.value
MikesExcelResults results = new MikesExcelResults();
results.value.AddRange(excelModels);
foreach (var model in results.value)
{
Console.WriteLine(String.Format("Name: {0}, Phone: {1}, Email: {2}", model.Name, model.Phone, model.Email));
}
Sample program

CSV to Nested JSON C#

I would like to convert a csv file into json with nested objects and nested array. The sample csv looks like below. My csv structure can be dynamic, but I am ok to keep it static to get the required format below. I know there are so many answers to similar questions, but none addressing my specific issue of nested objects.
Id,name,nestedobject/id,nestedarray/0/name
1,name,2,namelist
2,name1,3,namelist1
I want the json like below, specifically having trouble with column 3 & 4 (nested objects)
[{"Id": 1,
"name": "name",
"nestedobject": {
"id": 2
},
"nestedarray": [{
"name": "namelist"
}
]
},
{"Id": 2,
"name": "name1",
"nestedobject": {
"id": 3
},
"nestedarray": [
{"name": "namelist1"}]
}
]
Please note to keep the csv file structure dynamic I pass the datatype in the column name - for e.g.. "System.Int32:Id" will be my first column instead of "Id". How can I modify my code to account for the nested objects?
public static DataTable ReadCsvFile(string fileName)
{
DataTable oDataTable = new DataTable();
StreamReader oStreamReader = new StreamReader(fileName);
bool hasColumns = false;
List<string> ColumnNames = new List<string>();
string[] oStreamDataValues = null;
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine();
if(oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(',');
if(!hasColumns)
{
int i = 0;
foreach(string csvcolumn in oStreamRowData.Split(','))
{
string[] nameWithType = csvcolumn.Split(':');
DataColumn oDataColumn = new DataColumn(nameWithType[1], typeof(string));
ColumnNames.Add(nameWithType[1]);
var type = System.Type.GetType(nameWithType[0]);
oDataColumn.DataType = type;
oDataTable.Columns.Add(oDataColumn);
i = i + 1;
}
hasColumns = true;
}
else
{
DataRow oDataRow = oDataTable.NewRow();
for(int i = 0; i < ColumnNames.Count; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
oDataTable.Rows.Add(oDataRow);
}
}
}
oStreamReader.Close();
oStreamReader.Dispose();
return oDataTable;
}
I serialize the DataTable in the end
DataTable dt = ReadCsvFile(filePath);
dt.CaseSensitive = true;
var jsonData = JsonConvert.SerializeObject(dt);
With Cinchoo ETL, an open source library, you can do it as follows
string csv = #"Id,name,nestedobject/id,nestedarray/0/name, nestedarray/0/city, nestedarray/1/name, nestedarray/200/city
1,name,2,namelist10, citylist10,namelist11, citylist11
2,name1,3,namelist20, citylist20,namelist21, citylist21";
StringBuilder json = new StringBuilder();
using (var w = new ChoJSONWriter(json))
{
using (var r = ChoCSVReader.LoadText(csv).WithFirstLineHeader()
.Configure(c => c.NestedColumnSeparator = '/')
)
w.Write(r);
}
Console.WriteLine(json.ToString());
Output:
[
{
"Id": 1,
"name": "name",
"nestedobject": {
"id": 2
},
"nestedarray": [
{
"name": "namelist10",
"city": "citylist10"
},
{
"name": "namelist11"
}
]
},
{
"Id": 2,
"name": "name1",
"nestedobject": {
"id": 3
},
"nestedarray": [
{
"name": "namelist20",
"city": "citylist20"
},
{
"name": "namelist21"
}
]
}
]

'System.Collections.Generic.KeyValuePair<string,object>' does not contain a definition for 'work'

namespace WebApplication1.Site
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var accessToken = "" // Token
var client = new FacebookClient(accessToken);
dynamic myInfo = client.Get("me/friends", new { fields = "name,id,work" });
foreach (dynamic friend in myInfo)
{
foreach (dynamic work in friend.work ?? new[] { new { employer = new { name = string.Empty }, position = new { name = string.Empty } } })
{
Response.Write("Employer: " + work.employer.name);
}
}
}
}
}
I am getting the following error on line 21. I cannot figure out what is causing it.
'System.Collections.Generic.KeyValuePair' does not contain a definition for 'work'
Sample JSON Return from the Facebook GraphAPI. This is only the first three friends. There are closer to 4000 friends I am parsing, obviously this gives some context for the structure of the data:
{
"data": [
{
"name": "Mia xxx",
"id": "11381",
"work": [
{
"employer": {
"id": "100982923276720",
"name": "New-York Historical Society"
},
"location": {
"id": "108424279189115",
"name": "New York, New York"
}
}
]
},
{
"name": "Leilah xxx",
"id": "1133"
},
{
"name": "xxx,
"id": "1231",
"work": [
{
"employer": {
"id": "104362369673437",
"name": "Bye Bye Liver: The Philadelphia Drinking Play"
},
"location": {
"id": "101881036520836",
"name": "Philadelphia, Pennsylvania"
},
"position": {
"id": "121113421241569",
"name": "Actress/Bartender"
},
"description": "A sketch comedy/improv show every Saturday night at Downey's on South & Front. Come thirsty!",
"start_date": "2011-09"
},
{
"employer": {
"id": "100952634348",
"name": "Act II Playhouse"
},
"location": {
"id": "109249869093538",
"name": "Ambler, Pennsylvania"
},
"position": {
"id": "125578900846788",
"name": "My Fair Lady"
},
"description": "11 actor version of the classic musical.",
"start_date": "0000-00"
},
An alternative to relying on the dynamic is to capture and parse the JSON with JSON.net, it's designed for querying json data and is really much safer than using dynamic
http://json.codeplex.com/
And deserializing into classes:
http://dotnetbyexample.blogspot.ca/2012/02/json-deserialization-with-jsonnet-class.html
Look at this:
Response.Write("Employer: " + myInfo.work.employer.name);
I suspect you meant:
Response.Write("Employer: " + work.employer.name);
Put it this way - if that's not what you meant, what's the purpose of your work variable?

How do i add $ref to a JSONSchema?

I have a JSONSchema which will have some items . Now the schema/s that define those items need to be referred in the main schema ?
* one schema that you reference:
{
"id": "http://some.where/sub/schema#",
"type": "object",
"properties": {
"p1": {
"type": "integer",
"minimum": 12
}
}
}
--- * the main schema: ----
{
"id": "http://path.to/base/schema#",
"type": "array",
"items": {
"extends": {
"$ref": "http://some.where/sub/schema#/properties/p1"
},
"divisibleBy": 5
}
}
Also note , i will have multiple items in the item . I do not see a way of doing this in the api . Nor does the api allow me to add custom properties . How can i achieve this ? I am using JSON.net.
Since It will be too long for a comment, I'll post it as an answer. But You should work on it to customize according to your needs.
string oneSchema = #"{
""id"": ""http://some.where/sub/schema#"",
""type"": ""object"",
""properties"": {
""p1"": {
""type"": ""integer"",
""minimum"": 12
}
}
} ";
string main = #"
{
""id"": ""http://path.to/base/schema#"",
""type"": ""array"",
""items"": {
""extends"": {
""$ref"": ""http://some.where/sub/schema#/properties/p1""
},
""divisibleBy"": 5
}
}";
var JObjMain = (JObject)JsonConvert.DeserializeObject(main);
var jObjOther = (JObject)JsonConvert.DeserializeObject(oneSchema);
JToken src = JObjMain["items"]["extends"]["$ref"];
JToken reference = jObjOther["id"];
var path = src.ToString().Replace(reference.ToString(), "").Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
JToken j = jObjOther[path[0]];
for(int i=1;i<path.Length;i++)
{
j = j[path[i]];
}
src.Replace(j);
Console.WriteLine(JObjMain);

Categories