I have a .json file that looks like this:
[
{
"username": "John",
"currency": 8,
"pulls":
[
{
"character": "person"
},
{
"character": "loved one"
}
]
},
{
"username": "Mike",
"currency": 2,
"pulls":
[
{
"character": "noone"
}
]
},
{
"username": "Clara",
"currency": 5,
"pulls":
[
{
"character": "someone"
}
]
}
]
What I managed to do so far is modify "currency":
bool userExists = false;
string jsonPointsString = File.ReadAllText(userPath);
dynamic jsonObjects = JsonConvert.DeserializeObject(jsonPointsString);
foreach (var jsonObject in jsonObjects)
{
if (jsonObject["username"] == user)
{
jsonObject["currency"] += value;
string output = JsonConvert.SerializeObject(jsonObjects, Formatting.Indented);
File.WriteAllText(userPath, output);
userExists = true;
}
}
As well as add a completely new entry from scratch:
JsonCollection.User user = new JsonCollection.User();
user.username = username;
user.currency = 10;
using (StreamReader r = new StreamReader(userPath))
{
string json = r.ReadToEnd();
List<JsonCollection.User> users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(json);
users.Add(user);
newJson = JsonConvert.SerializeObject(users, Formatting.Indented);
}
File.WriteAllText(userPath, newJson);
However, no matter what I try I can not add another element to "pulls". The idea is that I call a function with a username and a pull, two strings. Based on the username variable I have to find the corresponding Json Entry and create a new entry within the "pulls" tree based on the pull variable. This is what I could come up with:
public void AddPullToUser(string user, string newPull)
{
user = "Mike"; //test value
string jsonPointsString = File.ReadAllText(userPath);
dynamic jsonObjects = JsonConvert.DeserializeObject(jsonPointsString);
foreach (var jsonObject in jsonObjects)
{
if (jsonObject["username"] == user)
{
//jsonObject["pulls"] = newPull;
JsonCollection.Character pull = new JsonCollection.Character();
pull.character = newPull;
jsonObject["pulls"] = pull;
string output = JsonConvert.SerializeObject(jsonObjects, Formatting.Indented);
File.WriteAllText(userPath, output);
}
}
}
If I do it like this the system can't convert the JsonCollection to the JArray but without using the JArray I don't understand how to find the specific users tree.
In step two this will have to be expanded even further to not create duplicated "pulls", but first of all this has to work in general.
Any help would be greatly appreciated.
Something like this -
var json = "[{'username':'John','currency':8,'pulls':[{'character':'person'},{'character':'loved one'}]},{'username':'Mike','currency':2,'pulls':[{'character':'noone'}]},{'username':'Clara','currency':5,'pulls':[{'character':'someone'}]}]";
var obj = JsonConvert.DeserializeObject<List<RootObject>>(json);
var o = obj.FindIndex(a => a.username == "Mike");
obj[o].pulls.AddRange(new List<Pull>{
new Pull{
character = "Modified"
}
});
Console.WriteLine(JsonConvert.SerializeObject(obj));
Where
public class Pull
{
public string character { get; set; }
}
public class RootObject
{
public string username { get; set; }
public int currency { get; set; }
public List<Pull> pulls { get; set; }
}
alternatively, you might be interested in JSON Merge
A possible solution looks like -
var json = "[{'username':'John','currency':8,'pulls':[{'character':'person'},{'character':'loved one'}]},{'username':'Mike','currency':2,'pulls':[{'character':'noone'}]},{'username':'Clara','currency':5,'pulls':[{'character':'someone'}]}]";
var obj = JArray.Parse(json);
var idx = obj.IndexOf(obj.FirstOrDefault(a => a["username"].ToString() == "Mike"));
((JArray)obj[idx]["pulls"]).Add(JObject.Parse(#"{
'character': 'new one'
}"));
Console.WriteLine(obj[idx]);
/*output -
{
"username": "Mike",
"currency": 2,
"pulls": [
{
"character": "noone"
},
{
"character": "new one"
}
]
} */
After a bit more research and your help I was able to first of all change all the interaction with Json to the same code-style.
New entry has changed to this:
public void CreateUser(string username)
{
try
{
string jsonUserString = File.ReadAllText(userPath);
var users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(jsonUserString);
users.AddRange(new List<JsonCollection.User> { new JsonCollection.User { username = username, currency = 10, pulls = new List<JsonCollection.Character> { new JsonCollection.Character { character = "TemmieHYPE" } } } });
string output = JsonConvert.SerializeObject(users, Formatting.Indented);
File.WriteAllText(userPath, output);
}
catch
{
Console.WriteLine("Error on CreateUser");
}
}
Update has changed to this:
public void UpdateUserStats(string username, decimal value, int selection)
{
try
{
string jsonUserString = File.ReadAllText(userPath);
var users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(jsonUserString);
int user = users.FindIndex(a => (a.username == username));
if (user != -1)
{
switch (selection)
{
case 1:
users[user].currency += value;
break;
case 2:
users[user].secondsOnline += value;
break;
default:
break;
}
string output = JsonConvert.SerializeObject(users, Formatting.Indented);
File.WriteAllText(userPath, output);
//AddPullToUser(username, DateTime.Now.ToString()); //remove on live
}
else
{
CreateUser(username);
}
}
catch
{
Console.WriteLine("Error on UpdateCurrency");
}
}
Most importantly the Add Pull command to add a nested element to the Json now works with the following code:
public void AddPullToUser(string username, string pulledCharacter)
{
string jsonUserString = File.ReadAllText(userPath);
var users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(jsonUserString);
int alreadyPulled = users.FindIndex(a => (a.username == username) && (a.pulls.FindIndex(b => b.character == pulledCharacter) > 0));
if (alreadyPulled == -1)
{
int user = users.FindIndex(a => (a.username == username));
users[user].pulls.AddRange(new List<JsonCollection.Character> { new JsonCollection.Character { character = pulledCharacter } });
string output = JsonConvert.SerializeObject(users, Formatting.Indented);
File.WriteAllText(userPath, output);
}
}
With the addition of the "if (alreadyPulled == -1)" duplicated pulls don't get added to the Json files either.
Related
I'm working on GitHub API and I want to manipulate the JSON response of this API so I have this API code
public class TrendRepo
{
public IEnumerable<object> Data;
}
[HttpGet]
public async Task<JsonResult> GetTrendingRepos()
{
var date = DateTime.Now.AddDays(-30).ToString("yyyy-MM-ddThh:mm:ssZ");
string trendingReposLanguagesUrl = #"https://api.github.com/search/repositories?q=created:>" + (date) + "&sort=stars&order=desc&per_page=10";
HttpWebRequest request = WebRequest.CreateHttp(trendingReposLanguagesUrl);
request.Accept = "application/json";
request.UserAgent = "request";
WebResponse response = await request.GetResponseAsync();
Stream data = response.GetResponseStream();
StreamReader reader = new StreamReader(data ?? throw new InvalidOperationException());
var readerResult = await reader.ReadToEndAsync();
//var jObj2 = JsonConvert.DeserializeObject<dynamic>(readerResult);
JToken token = JObject.Parse(readerResult);
var items = token["items"];
var arr = new List<object>();
List<dynamic> tripDetailsCollection = new List<dynamic>();
if (items != null)
{
foreach (dynamic o in items)
{
arr.Add(o.language);
arr.Add(o.id);
arr.Add(o.full_name);
arr.Add(o.html_url);
arr.Add(" ");
tripDetailsCollection.AddRange(arr);
}
}
TrendRepo trendRepo = new TrendRepo()
{
Data = arr,
};
return new JsonResult(trendRepo);
}
which return the response like this
{
"data": [
"Python",
319029846,
"beurtschipper/Depix",
"https://github.com/beurtschipper/Depix",
" ",
"C++",
311683390,
"WerWolv/ImHex",
"https://github.com/WerWolv/ImHex",
" ",
null,
316705066,
"peng-zhihui/PocketLCD",
"https://github.com/peng-zhihui/PocketLCD",
" "
]
}
but what I want is to be something like this
{
"data": [
"Python",
319029846,
"full_name":[
"beurtschipper/Depix",
"beurtschipper/Depix",
],
"https://github.com/beurtschipper/Depix",
" ",
]
"data": [
"C++",
311683390,
"full_name":[
"beurtschipper/Depix",
"WerWolv/ImHex",,
],
"https://github.com/WerWolv/ImHex",
" ",
]
"data": [
null,
316705066,
"full_name":[
"beurtschipper/Depix",
"WerWolv/ImHex",,
],
"https://github.com/peng-zhihui/PocketLCD",
" "
]
}
I tried to add another foreach within the existing one to kind of loop the
property but it gave me the same result.
also, I need to select a distinct language which is easy to do but
the trick move is I want all repos names and count which depend on this
language within the array, like in the JSON response I want above.
Any help I would be grateful.
#Hazeem, Spent bit time to see what we can do get the search results closer to your expectations, basically the way you defined JSON is useless no one would be able to parse, I don't think even serializer would accept for example data collection is not separated by commas, I tied up code a bit to work closer to what you want.
Code:
var tripDetailsCollection = new List<object>();
var date = DateTime.Now.AddDays(-30).ToString("yyyy-MM-ddThh:mm:ssZ");
string trendingReposLanguagesUrl = #"https://api.github.com/search/repositories?q=created:>" + (date) + "&sort=stars&order=desc&per_page=10";
var request = WebRequest.CreateHttp(trendingReposLanguagesUrl);
request.Accept = "application/json";
request.UserAgent = "request";
var response = await request.GetResponseAsync();
Stream data = response.GetResponseStream();
JToken token;
using (var reader = new StreamReader(data ?? throw new InvalidOperationException()))
{
var readerResult = await reader.ReadToEndAsync();
token = JObject.Parse(readerResult);
}
if (token != null)
{
var items = token["items"];
if (items != null)
{
foreach (dynamic o in items)
{
var arr = new
{
data = new List<object>
{
o.language,
o.id,
o.full_name,
o.html_url,
" "
}
};
tripDetailsCollection.Add(arr);
}
}
}
var json = JsonConvert.SerializeObject(tripDetailsCollection);
Result - you should be able loop through the collection and use it elsewhere.
What I need is to wrap my TrendRepo class with the Parent class with the same property values and DeserializeObject of the instead of here's the answer and feel free if anything not obvious.
public class Root
{
[JsonPropertyName("items")]
public List<Items> Items { get; set; }
}
public class Items //TrendRepo
{
[JsonPropertyName("language")]
public string Language { get; set; }
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("full_name")]
public string Full_Name { get; set; }
public string total_count { get; set; }
}
and edit the API like this
var readerResult = await reader.ReadToEndAsync();
Root jObj2 = JsonConvert.DeserializeObject<Root>(readerResult);
var result = jObj2.Items.Select(x => new
{
x.Language,
x.Id,
x.Full_Name,
x.Name
}).GroupBy(x => x.Language).ToArray();
return new JsonResult(result);
I have json example "TestConfigIdMapping.json":
{
"schema": "None",
"TestMapping": [
{
"testId": "test_1",
"testConfigs": [
"platform1",
"platform2",
"platform3",
]
},
{
"testId": "test_2",
"testConfigs": [
"platform2"
]
}
]
}
Using Newtonsoft.Json c# library, how would I add json object element:
{
"testId": "test_3",
"testConfigs": [
"platform1",
"platform3"
]
}
to the above already loaded json file?
My code using form1 and display json in form2:
class JsonTestMapping
{
[JsonProperty("schema")]
string Schema = "None";
[JsonProperty("TestConfigMapping")]
public JsonObjects[] testConfigMapping { get; set; }
}
class JsonObjects
{
[JsonProperty("testId")]
public string TestId { get; set; }
[JsonProperty("testConfigs")]
public string[] TestConfigs { get; set; }
}
class LoadJson
{
public string jsonValues = File.ReadAllText(#"C:\GITTest\TestIdConfigMapping.json");
}
JsonObjects jsonObjects = new JsonObjects()
{
TestId = f1.Form1textbox.Text,
TestConfigs = new string[]
{
// set FormTextbox2 modifier = public
f1.FormTextbox2.Text
}
};
The following is Form2 popup and displays json:
private void Form2_Load(object sender, EventArgs e)
{
Form2TextBox.ReadOnly = true;
Form2TextBox.Multiline = true;
Form2TextBox.ScrollBars = ScrollBars.Vertical;
Form2TextBox.WordWrap = true;
//string convertJsonFileSerialized = JsonConvert.SerializeObject(readJsonFile.jsonText);
//List<ReadJsonFile> convertJsonFileDeserialized = JsonConvert.DeserializeObject<List<ReadJsonFile>>(readJsonFile.jsonText);
//string finalJson = JsonConvert.SerializeObject(convertJsonFileDeserialized);
LoadJson loadJson = new LoadJson();
string myJsonValues = loadJson.jsonValues;
JObject rss = JObject.Parse(myJsonValues);
JArray TestConfigMapping = (JArray)rss["TestConfigMapping"];
//List<JsonObjects> myList = JsonConvert.DeserializeObject<List<JsonObjects>>(myjsonRead);
JsonObjects jsonObjects = new JsonObjects()
{
TestId = f1.Form1textbox.Text,
TestConfigs = new string[]
{
// set FormTextbox2 modifier = public
f1.FormTextbox2.Text
}
};
List<JsonObjects> jsonList = new List<JsonObjects>();
jsonList.Add(jsonObjects);
string jsonResult1 = JsonConvert.SerializeObject(jsonObjects, Formatting.Indented);
JsonTestMapping jsonTestConfigMapping = new JsonTestMapping()
{
testConfigMapping = new JsonObjects[]
{
jsonObjects
}
};
string jsonResult = JsonConvert.SerializeObject(jsonTestConfigMapping, Formatting.Indented);
//ReadJsonFile readJsonFile = new ReadJsonFile();
//string jsonResult2 = readJsonFile.jsonText;
Form2TextBox.Text = rss.ToString();
}
The goal is to have Form 1, with 2 text box inputs that insert the "TestID" & "TestConfigs". Upon clicking button1, convert the 2 input texts into Json format and upon clicking "append" button, asserts the formatted Json object element into the already existing json file configuration.
I am trying to create the json from c# object which holds the data.
Data is in simple table format. Consist of Columns: Name, InputCode, DisplayID, CodeID, ParentID.
If Parent(Net) then ParentID is null. If Children(Subnet), has ParentID that holds CodeID of Parent(Net).
CodeID is Unique.
I am facing the issue with iternation under subnet using foreach. It dosen't allow.
public class CodeFrameJson
{
public string Name { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public int? InputCodeValue { get; set; }
public int DisplayId { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<CodeFrameJson> Subnet { get; set; }
}
List<CodeFrameJson> cfj = new List<CodeFrameJson>();
IEnumerable<CodeDTO> _cfd = new List<CodeDTO>();
_cfd = codeFrameJson.GetCodeFrame(questionId, projectName);
_cfd = _cfd.OrderBy(a => a.DisplayOrderNo).ToList();
foreach (var a in _cfd)
{
int CodesID = 0;
CodeFrameJson obj = new CodeFrameJson();
if (a.InputCodeValue == null)
{
var root = new CodeFrameJson()
{
Name = a.CodeName,
DisplayId = a.DisplayOrderNo,
InputCodeValue = null,
Subnet = new List<CodeFrameJson>()
{
//Start: Not allowing foreach
foreach (var x in _cfd)
{
if (x.ParentId == CodesID)
{
new CodeFrameJson()
{
Name = x.CodeName,
InputCodeValue = x.InputCodeValue,
DisplayId = x.DisplayOrderNo
};
}
}
//End: Not allowing foreach
}
};
obj = root;
}
else {
var root = new CodeFrameJson()
{
Name = a.CodeName,
DisplayId = a.DisplayOrderNo,
InputCodeValue = a.InputCodeValue,
Subnet = null
};
obj = root;
}
cfj.Add(obj);
}
var json = JsonConvert.SerializeObject(cfj, Formatting.Indented);
Final Output Something like this which can be distinguished easily
{
"Site": {
"Name": "Site",
"DisplayID": 1,
"Subnet": [
{
"Name": "Full Site",
"InputCodeValue": 1,
"DisplayId": 2
},
{
"Name": "Partial Site",
"InputCodeValue": 2,
"DisplayId": 3
}
]
},
"Test": {
"Name": "Test1",
"InputCodeValue": 3,
"DisplayId": 4
}
}
This doesn't really have to do anything with JSON, but with object (collection) initialization. You can only assign values there, but LinQ comes to the rescue:
Simply filter your list and create the new objects in the select statement:
Subnet = _cfd.Where(x => x.ParentId == CodesID).Select(x => new CodeFrameJson
{
Name = x.CodeName,
InputCodeValue = x.InputCodeValue,
DisplayId = x.DisplayOrderNo
}).ToList()
I have a Json Object like the one below.
"log": {
"Response": [
{
"#type": "Authentication",
"Status": "True",
"Token": "cc622e9c-0d56-4774-8d79-543c525471b4"
},
{
"#type": "GetApplication",
"AppId": 100,
"Available": "True"
}]}
I need to access the appId property. I have tried the below code which gives the null reference error. Please help me figure out the mistake.
dynamic JsonText = JObject.Parse(result);
string AppId= JsonText ["log"]["Response #type='GetApplication'"]["AppId"].Tostring();
Here dotNetFiddle
string json = #"{
""log"": {
""Response"": [{
""#type"": ""Authentication"",
""Status"": ""True"",
""Token"": ""cc622e9c-0d56-4774-8d79-543c525471b4""
}, {
""#type"": ""GetApplication"",
""AppId"": 100,
""Available"": ""True""
}]
}
}";
JObject result = JObject.Parse(json);
foreach(var item in result["log"]["Response"])
{
Console.WriteLine(item["#type"]);
Console.WriteLine(item["AppId"]);
}
You don't need to use dynamic, use JObject and after that loop in the Responses and take the #type
To to access the AppId property like the way you are showing in your example:
string AppId = JObject.Parse(result)["log"].SelectToken("$.Response[?(#.#type=='GetApplication')]")["AppId"].ToString();
You can use http://json2csharp.com/ and generate model class, using Newtonsoft.Json and LINQ get id as I show.
model class
public class Response
{ [JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("Status")]
public string Status { get; set; }
[JsonProperty("Token")]
public string Token { get; set; }
[JsonProperty("AppId")]
public int? AppId { get; set; }
[JsonProperty("Available")]
public string Available { get; set; }
}
public class Log
{
public List<Response> Response { get; set; }
}
public class RootObject
{
public Log log { get; set; }
}
.cs
var results = JsonConvert.DeserializeObject<RootObject>(json);
var id= results.log.Response.FirstOrDefault(d => d.Type == "GetApplication").AppId;
string json = #"{
""log"": {
""Response"": [{
""#type"": ""Authentication"",
""Status"": ""True"",
""Token"": ""cc622e9c-0d56-4774-8d79-543c525471b4""
}, {
""#type"": ""GetApplication"",
""AppId"": 100,
""Available"": ""True""
}]
}
}";
JObject obj = JObject.Parse(result);
string AppId = obj["log"]["Response"][1]["AppId"].ToString();
Console.WriteLine(AppId);
#user3064309 hi, if ("#type": "GetApplication") is the second and not change location. so you can use obj["log"]["Response"][1]["AppId"].ToString();
I have written an extension function that will be the third level of depth. You can make its depth as generic if you need, so the code below
public static object GetJsonPropValue(this object obj, params string[] props)
{
try
{
var jsonString = obj.ToString().Replace("=", ":");
var objects = JsonConvert.DeserializeObject<dynamic>(jsonString);
foreach (var o in objects)
{
JObject jo = JObject.Parse("{" + o.ToString().Replace("=", ":") + "}");
if (props.Count() == 1 && jo.SelectToken(props[0]) != null)
return jo.SelectToken(props[0]).ToString();
if (props.Count() == 2 && jo.SelectToken(props[0])?.SelectToken(props[1]) != null)
return jo.SelectToken(props[0])?.SelectToken(props[1]).ToString();
if (props.Count() == 2 && jo.SelectToken(props[0])?.SelectToken(props[1])?.SelectToken(props[2]) != null)
return jo.SelectToken(props[0])?.SelectToken(props[1])?.SelectToken(props[2]).ToString();
}
}
catch (Exception ex)
{
throw new ArgumentException("GetJsonPropValue : " + ex.Message);
}
return null;
}
Also i written an extension for normal c# objects, getting prop value dynamically
public static object GetPropValue(this object obj, Type typeName, string propName)
{
try
{
IList<PropertyInfo> props = new List<PropertyInfo>(typeName.GetProperties());
foreach (PropertyInfo prop in props)
{
if (prop.Name == propName)
{
object propValue = prop.GetValue(obj, null);
return propValue;
}
}
}
catch (Exception ex)
{
throw new ArgumentException("GetPropValue : " + ex.Message);
}
return null;
}
How can we parse this simple json using proper class & member variables
{
"item": [
{
"id": 12,
"name": "Johnny"
},
{ "id":13,
"name":"mohit"
}
]
}
obviously u can use the Newtonsoft.Json(Json.NET)
and call a method return with a anonymous type.
like this:
var anType = new
{
multiResult = new
{
results = new[]
{
new
{
description = string.Empty,
title = string.Empty,
picUrl = string.Empty,
totalTime = 0,
outerPlayerUrl = string.Empty,
picChoiceUrl = new string[] { "", "" }
}
}
}
};
//get info from JsonString
var tudou = JsonConvert.DeserializeAnonymousType(jsonString, anType);
return VideoDetail.CreateSimpleInstance(DateTime.Now,
tudou.multiResult.results[0].title,
tudou.multiResult.results[0].description,
tudou.multiResult.results[0].picUrl,
tudou.multiResult.results[0].outerPlayerUrl);
}