Parsing through complex json in C# - c#

I am attempting to parse through the following to determine the Name and Goals of the top scoring Player for the specific "AC Milan" in this json file that contains many other teams and countries. The main issue I have been running into when I parse it as a JObject is the inability to parse a JObject as a JArray as this json file is pretty messy.
Unhandled exception. System.InvalidCastException: Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.

you have a json array, so you have to use for parsing JArray, not JObject
var jsonParsed=JArray.Parse(json);
and IMHO you posted an invalid json, it needs "{" before "AC Milan". So it should be like this
[
{
"Italy": [
{
"SerieA": [
{
"ACMilan": [
{
"Name": "Player1",
"Goals": 3
},
{
"Name": "Player2",
"Goals": 5
}
]
}
]
}
]
}
]
in this case you can use this query
List<Score> milanPlayersList = JArray.Parse(json)
.Select(i=> ((JObject) i).Properties().FirstOrDefault(x => x.Name=="Italy" ).Value).First()
.Select(i=> ((JObject) i).Properties().FirstOrDefault(x => x.Name=="SerieA" ).Value).First()
.Select(i=> ((JObject) i).Properties().FirstOrDefault(x => x.Name=="ACMilan" ).Value).First()
.Select(i=> i.ToObject<Score>()).ToList().Dump();
using this list you can make any kind of queries.
result
[
{
"Name": "Player1",
"Goals": 3
},
{
"Name": "Player2",
"Goals": 5
}
]
class
public class Score
{
public string Name { get; set; }
public int Goals {get; set;}
}

Related

How can I access my nested data using variables C#

I have a json file and I deserialised it as shown in the code below. Some context, dex is a robot and it has information such as battery and so on as shown in the json file below. I want to read the battery status for the robot that the user selected ( robot).
This is my code, currently im only accessing data.dex but i want to change it to whichever data.robot, where robot is a variable
var data = JsonConvert.DeserializeObject<Root>(json);
var robot = queryDetails2.Amr;
var text =$"";
if (data.dex.battery.status == "good")
{
text = $"{queryDetails2.Amr}'s battery is in good condition. ";
}
This is the json file:
{
"dex":
{
"current_job":
{"job":null, "task": null, "location": null},
"battery":
{"name":"battery", "status": "good", "value": "100"},
},
"dex_1":
{
"current_job":
{"job":null, "task": null, "location": null},
"battery":
{"name":"battery", "status": "good", "value": "100"},
},
"dex_2":
{
"current_job":
{"job":null, "task": null, "location": null},
"battery":
{"name":"battery", "status": "good", "value": "100"},
}
}
I wanted to use the GetMethod or the solution as suggested in this question (https://stackoverflow.com/questions/53076743/how-to-access-variable-of-a-nested-functions-in-python[1]).
However, im getting errors like it does not have a method. Now im confused, was it because i used var? but the deserialised method converts the json to an object though..
Anyway, how should i approach this?
Assuming that you have 3 robots with different names: dex, dex_1 and dex_2, you should reorganize your solution to treat the json data as a list of Robots instead of 3 separate variables for each robot.
To do this, first your json should look like this:
{
"robots":[
{
"name":"dex",
"current_job":{
"job":null,
"task":null,
"location":null
},
"battery":{
"name":"battery",
"status":"good",
"value":"100"
}
},
{
"name":"dex_1",
"current_job":{
"job":null,
"task":null,
"location":null
},
"battery":{
"name":"battery",
"status":"good",
"value":"100"
}
},
{
"name":"dex_2",
"current_job":{
"job":null,
"task":null,
"location":null
},
"battery":{
"name":"battery",
"status":"good",
"value":"100"
}
}]
}
Next, update your serialization classes. Add a field called name in the Robot class or whatever class type you currently have for data.dex. In Root, remove the "dex" fields and add a List<Robot>.
public class Root
{
public List<Robot> robots { get; set; }
}
public class Robot
{
public string name { get; set; }
public Job current_job { get; set;}
public Battery battery{ get; set; }
}
Now you can write whatever logic to get the right robot data. Here is an example using System.Linq:
var robotName = "dex_2";
var robotInfo = data.robots.First(x => x.name.Equals(robotName));
var text = $"{robotName}'s battery is in {robotInfo.battery.status} condition.";

MongoDB with C# Driver: How to filter on field within nested array of objects

I'm new to MongoDB and have been struggling with this a bit. Let's say I have a document with an id, name, and array of objects:
{
"_id": {
"$oid": "614ba49b46727413d60b99e2"
},
"Name": 1,
"ObjectArray": [
{
"ObjectId": {
"$oid": "614ba49b46727413d60b99e3"
},
"Value": "some value",
},
{
"ObjectId": {
"$oid": "614ba49b46727413d60b99e5"
},
"Value": "other value",
}
],
}
I have a C# class that maps to this document and everything works in that regard. Let's say I want to add another object to the object array only if the new object's Id doesn't already exist in the array? I'm using C# Driver for this and have tried several things.
I've tried several ideas including the following --
var filter = FilterBuilder.Eq(x => x.Id, id) &
FilterBuilder.Nin(x => x.ObjectArray[-1].ObjectId, new[] { newDoc.ObjectId});
This unfortunately only checks the first object in the object array. So as asked before how do I only add a new object to an array if a condition exists all within one filter?
Thanks for your time.
*** Solution ***
Used Elematch in conjunction with Not to do the filtering all in one.
var filter = FilterBuilder.Eq(x => x.Id, id) &
FilterBuilder.Not(FilterBuilder.ElemMatch(x => x.ObjectArray,
Builders<ObjectClass>.Filter.Eq(y => y.ObjectId, newDoc.ObjectId)));
You can use $elemMatch to access and filter nested property. And compare the value with $eq.
{
"ObjectArray": {
$elemMatch: {
"ObjectId": {
$eq: <value>
}
}
}
}
Complete MongoDB aggregation query
db.collection.aggregate([
{
$match: {
$and: [
{
"_id": {
// With Exist _id
$eq: ObjectId("614ba49b46727413d60b99e2")
}
},
{
"ObjectArray": {
$elemMatch: {
"ObjectId": {
// With unexist ObjectArray.ObjectId
$eq: ObjectId("614ba49b46727413d60b99e3")
}
}
}
}
]
}
}
])
Sample Mongo Playground
For MongoDB .NET/C# driver
var filter = FilterBuilder.Eq(x => x.Id, id) &
FilterBuilder.ElemMatch(x => x.ObjectArray,
Builders<ObjectClass>.Filter.Eq(y => y.ObjectId, newDoc.ObjectId);
Replace ObjectClass with the class name for the Object in ObjectArray.
Remarks:
With the above solution, it will return the document when the parsed ObjectId is existed in ObjectArray. Hence you should do the handling for the existed ObjectId case.
And add the document to ObjectArray only when no document is queried.
References
$elemMatch
Similar scenario for filtering a document in an array with MongoDB .NET/C# driver

In C#, how can i deserialize this json?

I am getting this JSON data back from a REST service that looks like this:
[ [ [ {"Name": "Joe", "Comment": "Load", "Updated": null, "Test": ""} ] ] ]
or
[ [ [ {"Name": "Joe", "Comment": "Load", "Updated": null, "Test": ""}, {"Name": "Bill", "Comment": "123", "Updated": null, "Test": ""} ] ] ]
I did a "Copy JSON as classes" feature in visual studio and it created this:
public class Rootobject
{
public Project[][][] Property1 { get; set; }
}
public class Project
{
public string Name { get; set; }
public string Comment { get; set; }
public string Updated { get; set; }
public string Test { get; set; }
}
but when i try to deserialize using this code:
var results = new JsonDeserializer().Deserialize<Rootobject>(response);
I get an error stating:
An exception of type 'System.InvalidCastException' occurred in RestSharp.dll but was not handled in user code
Additional information: Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'
Could you please advise on what I might be doing wrong (NOTE: i don't have any control over how the data comes in so changing the format isn't an option)
Also, to confirm this seems to be valid JSON from JSONLlint:
Using Newtonsoft.Json nuget package,
try
JSONConvert.DeserialiseObject<Rootobject>(response)
EDIT: BTW, I tried to use your json on http://json2csharp.com/ and it says Parsing your JSON didn't work. Please make sure it's valid. So I doubt that any json parsing library will be able to parse your JSON.
However implementing your own deserializer is possible and an ideal solution when external services return invalid JSON
I can probably help you deserialize it if you show me what JSON you get when service returns multiple Project objects.
EDIT2: Szabolcs's solutions seems promising, but I would still suggest testing it with JSON for multiple Product objects. I smell something bad & its the shitty third party service. Always good to test.
You can deserialize that particular JSON like this using Json.NET:
var json = "[ [ [ {\"Name\": \"Joe\", \"Comment\": \"Load\", \"Updated\": null, \"Test\": \"\"}, "+
" {\"Name\": \"Bill\", \"Comment\": \"123\", \"Updated\": null, \"Test\": \"\"} ] ] ]";
var deserializedObject = JsonConvert.DeserializeObject<List<List<List<Project>>>>(json);
And to get all the Projects from the nested lists:
var allProjects = deserializedObject.SelectMany(x => x.SelectMany(y => y)).ToList();

retrieve item from a json file c#

{
"_id": "underscore",
"_rev": "136-824a0ef7436f808755f0712c3acc825f",
"name": "underscore",
"description": "JavaScript's functional programming helper library.",
"dist-tags": {},
"versions": {
"1.0.3": {
"name": "xxx",
"description": "xxx"
},
"1.0.4": {},
"1.1.0": {}
}
}
I would like to retrieve the latest version(1.1.0) from the json file. However, it always gives out me errors of "can not deserialize json object into type RootObject
Here is my class
public class versions
{
public string name { get; set; }
public string description { get; set; }
}
public class RootObject
{
public List<versions> vs { get; set; }
}
And here is where I used it
RootObject[] dataset = JsonConvert.DeserializeObject<RootObject[]>(json);
Any idea. Many thankx
Update:
I have updated the JSON file format, but some problem..
I think the problem is, that in JSON you have to quote all "field"/attribute names. (Thats a difference from standard Javascript-Notation, where you can have unquoted attributes).
So, your file should be like:
{
"_id" : "underscore",
"versions": {
"1.0.3" : {
"name": "xxx",
"description": "xxx"
}
}
Note that {1.0.3: { name: "xxx" } } wouldn't be valid JavaScript either since '1.0.3' is an invalid identifier in JavaScript.
Looking at the JSON in your updated answer:
{
"_id" : "underscore",
"versions": {
"1.0.3" : {
"name": "xxx",
"description": "xxx"
},
"1.0.4" : {
"name": "xxx",
"description": "xxx"
}
}
This is still Invalid JSON - you have 4 opening { and only 3 closing }
you should use http://jsonlint.com/ - to validate your JSON and ensure it is Valid
I've fixed your json in question. Now for your real question
I would like to retrieve the latest version(1.1.0) from the json file. However, it always gives out me errors of "can not deserialize json object into type RootObject
You have property names like 1.0.3 that are unknown at compile time. So you can not deserialize them to a concrete class. You should handle them dynamically.
Try this:
var versions = JObject.Parse(json)["versions"]
.Children()
.Cast<JProperty>()
.ToDictionary(c => c.Name, c => c.Value.ToObject<versions>());

Show json data in view in ASP.NET MVC3?

I am developing facebook app in which i am fetching user's friend detail in as
dynamic result = client.Get("me/friends"); //it gives friend's data for id, name
it gives data in
{
"data": [
{
"name": "Steven",
"id": "57564897"
},
{
"name": "Andy",
"id": "8487581"
}
}
Now i would like to parse this data and store it. so that i can use it my way.
I was trying to parse it using JSON.NET and show the data in view as
var model = JsonConvert.DeserializeObject<FriendDetail>(result.data);
in the class :
public class FriendDetail
{
public string id { get; set; }
public string name { get; set; }
public FriendDetail(string i, string n)
{
id = i;
name = n;
}
}
Now so that i can pass the view as "return View(model)"
But its giving me error: The best overloaded method match for 'Newtonsoft.Json.JsonConvert.DeserializeObject<FBApp.Models.FBFriendDetail>(string)' has some invalid arguments
Why this error is occurring ?
Please help me to parse this json data.
Also is there any better way to parse and Store json data and also then show in view ?
Please help
You are trying to deserialize a list of FriendDetail objects into a single FriendDetail object. Try the following:
var jObject = JObject.Parse(result.ToString());
var model = JsonConvert.DeserializeObject<List<FriendDetail>>(jObject["data"].ToString());
EDIT
This is how I tested it:
var result =
#"{
""data"": [
{
""name"": ""Steven"",
""id"": ""57564897""
},
{
""name"": ""Andy"",
""id"": ""8487581""
}]
}";
var jObject = JObject.Parse(result.ToString());
var model = JsonConvert.DeserializeObject<List<FriendDetail>>(jObject["data"].ToString());

Categories