Parsing JSONObject - c#

I am trying to GET JSON From a webservice , which i was able to figure out .
BTW This was my JSON Data -
{
"X-YZ-111/AB.CD": {
"P1": "F",
"P2": "43.46"
},
"X-YZ-112/AB.CD": {
"P1": "F",
"P2": "8.02"
},
"X-YZ-113/AB.CD": {
"P1": "F",
"P2": "9066.58"
},
"X-YZ-114/AB.CD": {
"P1": "F",
"P2": "6.00"
},
"X-YZ-115/AB.CD": {
"P1": "F",
"P2": "6.00"
},
"X-YZ-116/AB.CD": {
"P1": "F",
"P2": "10.00"
}}
Using Windows.Data.Json;
private async void getJSON_click(object sender,RoutedEventArgs e)
{
var client=new HttpClient();
client.MaxResponseBufferSize=1024*1024;
var response= await Client.GetAsync(new Uri(The URL here));
var result = await response.Content.ReadAsStringAsync();
var component=JsonObject.Parse(result);
}
Now i am able trying to parse it into a collection,where each item has "X-YZ-111/AB.CD" as name property and P1 and P2 as other 2 properties ,which i will try to bind to a Tile in UI using CollectionViewSource later.
Now This is the C# classes Json2CShardpDotCom is generating
public class Name
{
public string Type { get; set; }
public string Val { get; set; }
}
public class Root
{
public Name Name { get; set; }
}
Any suggestions on how to loop through these values using foreach and what classes i should make in C#?
Edit 1: BTW i know there has to be an dictionary where i first do a foreach on outer loop to retrieve the Name and foreach on inner loop to retrieve the P1 and P2.
But i am confused regarding what classes i should use in C# to consume JSON and create collection item out of my JSON

i am confused regarding what classes i should use in C# to consume JSON and create collection item out of my JSON
You don't need any class. Just a little bit Linq
I would use Json.Net for this
var jObj = JObject.Parse(result);
var dict = jObj.Children()
.Cast<JProperty>()
.ToDictionary(p => p.Name,
p => new Tuple<string, string>((string)p.Value["P1"], (string)p.Value["P2"]));
That is all. Sample usage would be:
foreach (var kv in dict)
{
Console.WriteLine("{0}: {1} {2}", kv.Key, kv.Value.Item1, kv.Value.Item2);
}
EDIT
Same code using JsonObject
var jObj = JsonObject.Parse(json);
var dict = jObj.Cast<KeyValuePair<string, JsonValue>>()
.ToDictionary(j=>j.Key,
j=>new Tuple<string,string>(j.Value["P1"],j.Value["P2"]));

Related

Json combine two files for a large value

Here are two json samples.
I want to combine this json into a file.
If a key exists in a value that is combined without thinking, it is difficult to replace only the value that is high in value.
First Sample.
{
"employees": [
{
"firstName": "Tom",
"HighValue": "3"
},
{
"firstName": "Maria",
"HighValue": "4"
},
{
"firstName": "Robert",
"HighValue": "45"
}
]
}
Second Sample.
{
"employees": [
{
"firstName": "Tom",
"HighValue": "6"
},
{
"firstName": "Maria",
"HighValue": "4"
},
{
"firstName": "Robert",
"HighValue": "45"
},
{
"firstName": "John",
"HighValue": "1"
}
]
}
I want Result:
{
"employees": [
{
"firstName": "Tom",
"HighValue": "6"
},
{
"firstName": "Maria",
"HighValue": "4"
},
{
"firstName": "Robert",
"HighValue": "45"
},
{
"firstName": "John",
"HighValue": "1"
}
]
}
The goal is to combine two samples, Json, into one result json. What's the best way?
One simple approach would be by making use of a json framework like Json.NET which handles serialization/deserialization for you.
First create a data model into which your json data can be deserialized to. I used the online tool json2csharp for this. This will give you the following model:
public class Employee
{
public string firstName { get; set; }
public int HighValue { get; set; }
}
public class RootObject
{
public List<Employee> employees { get; set; }
}
Now you can simply deserialize your json strings into objects like this:
string json1 = "";
string json2 = "";
var obj1 = JsonConvert.DeserializeObject<RootObject>(json1);
var obj2 = JsonConvert.DeserializeObject<RootObject>(json2);
After this step you just have to iterate over your employees, check if they exist in both lists and add/update them accordingly:
foreach(var emp in obj2.employees)
{
Employee existing = null;
try
{
existing = obj1.employees.SingleOrDefault(e => e.firstName == emp.firstName);
}
catch(Exception ex)
{
// The same employee exists multiple times in the first list
}
if(existing != null)
{
// obj1 already contains an employee with the given name, check which value is bigger
if(existing.HighValue < emp.HighValue)
{
// The value of the existing employee is smaller
// -> Update the value with the value from the second object
existing.HighValue = emp.HighValue;
}
}
else
{
// obj1 does not already contain an employee with the given name, add the whole employee
obj1.employees.Add(emp);
}
}
Now obj1 contains the combined list of employees.
To serialize the combined list back to json do the following:
var json = JsonConvert.SerializeObject(obj1);
(For the record JSON isn't one of my strongest points but I thought answering this for you would be a good challenge)
The following code takes both JSON samples as JObjects using Newtonsoft.Json, then merges the two samples together. I then use LINQ to group and select the people with the highest values and output a new array.
The advantage to this solution is if you only want to use C# to merge, not use it for any other logic, you don't need to deserialize to an object.
Give it a try:
var firstSample = JObject.Parse("Your first sample goes here");
var secondSample = JObject.Parse("Your second sample goes here");
var newJsonArray = new JArray(); //Makes new array for output
firstSample.Merge(secondSample); //Merges the firstSample JObject with secondSample JObject
var filteredJson = firstSample["employees"] //Makes new JObject with filtered values
.GroupBy(x => x["firstName"]) // Groups by the first name
.Select(x => x.Where(y => y["HighValue"] == x.Max(z => z["HighValue"]))) // Select the employee in each group with the highest value
.ToList(); // Converts to a list out
foreach (var token in filteredJson)
{
newJsonArray.Add(token); // For each selected employee, add it to the new array
}
var outputJson = new JObject(new JProperty("employees", newJsonArray)); // Composes the new JSon string

Get Key / Value of JSON object with Newtonsoft

I see many questions and answers about what I'm trying to do but after reading the answers I'm not able to get the key and value out of this json.
Here is the json being returned:
{
"#odata.context": "https://con813-crm612cf723bbf35af6devaos.cloudax.dynamics.com/data/$metadata#Customers(CustomerAccount,Name)",
"value": [
{
"#odata.etag": "W/\"JzAsMjI1NjU0MjE1NTg7MCwwOzAsNTYzNzE0NTMyODswLDU2MzcxNDQ1NzY7MCwyMjU2NTQyNTY5MzswLDIyNTY1NDI3MjM2OzAsMDswLDIyNTY1NDI3MjM2OzAsMjI1NjU0MjcyMzY7MCwwJw==\"",
"CustomerAccount": "DE-001",
"Name": "Contoso Europe"
},
{
"#odata.etag": "W/\"JzAsMjI1NjU0MjE1NTk7MCwwOzAsMzU2MzcxNDkxMTI7MCw1NjM3MTQ0NTc3OzAsMjI1NjU0MjU2OTQ7MCwyMjU2NTQyNzIzODswLDA7MCwyMjU2NTQyNzIzODswLDIyNTY1NDI3MjM4OzAsMCc=\"",
"CustomerAccount": "US-001",
"Name": "Contoso Retail San Diego"
},
{
"#odata.etag": "W/\"JzAsMjI1NjU0MjE1NjA7MCwwOzAsMzU2MzcxNDkxMTM7MCw1NjM3MTQ0NTc4OzAsMjI1NjU0MjU2OTU7MCwyMjU2NTQyNzI0MDswLDA7MCwyMjU2NTQyNzI0MDswLDIyNTY1NDI3MjQwOzAsMCc=\"",
"CustomerAccount": "US-002",
"Name": "Contoso Retail Los Angeles"
}
]
}
I need to get the names of the keys, which is "CustomerAccount" and "Name" in this example, and then their values. I can't figure out to just return those values.
JObject parsedJson = JObject.Parse(_json);
StringBuilder builder = new StringBuilder();
foreach (JProperty property in parsedJson.Properties())
{
builder.Append((string.Format("Name: [{0}], Value: [{1}].", property.Name, property.Value)));
}
Hoping to add more clarity; In this example I would like to write out the key/values after "#odata.etag" which the keys are "CustomerAccount" and "Name" and their values are after the colon. The keys/values are dynamic so I need to loop through writing out whatever the key names and values are after each "#odata.etag" value.
Use JsonConvert.DeserializeObject and pass the type of object you want to parse. there was a missing closing curly brace at the end. I hope I understood what you want to do correctly, if not plz leave a comment
class Value
{
public string CustomerAccount { get; set; }
public string Name { get; set; }
}
class Customer
{
public List<Value> Value { get; set; }
}
class Program
{
static void Main(string[] args)
{
var obj = JsonConvert.DeserializeObject<Customer>(#" {
'#odata.context': 'https://con813-crm612cf723bbf35af6devaos.cloudax.dynamics.com/data/$metadata#Customers(CustomerAccount,Name)',
'value': [
{
'#odata.etag': 'W/\'JzAsMjI1NjU0MjE1NTg7MCwwOzAsNTYzNzE0NTMyODswLDU2MzcxNDQ1NzY7MCwyMjU2NTQyNTY5MzswLDIyNTY1NDI3MjM2OzAsMDswLDIyNTY1NDI3MjM2OzAsMjI1NjU0MjcyMzY7MCwwJw==\'',
'CustomerAccount': 'DE-001',
'Name': 'Contoso Europe'
},
{
'#odata.etag': 'W/\'JzAsMjI1NjU0MjE1NTk7MCwwOzAsMzU2MzcxNDkxMTI7MCw1NjM3MTQ0NTc3OzAsMjI1NjU0MjU2OTQ7MCwyMjU2NTQyNzIzODswLDA7MCwyMjU2NTQyNzIzODswLDIyNTY1NDI3MjM4OzAsMCc=\'',
'CustomerAccount': 'US-001',
'Name': 'Contoso Retail San Diego'
},
{
'#odata.etag': 'W/\'JzAsMjI1NjU0MjE1NjA7MCwwOzAsMzU2MzcxNDkxMTM7MCw1NjM3MTQ0NTc4OzAsMjI1NjU0MjU2OTU7MCwyMjU2NTQyNzI0MDswLDA7MCwyMjU2NTQyNzI0MDswLDIyNTY1NDI3MjQwOzAsMCc=\'',
'CustomerAccount': 'US-002',
'Name': 'Contoso Retail Los Angeles'
}
]
}");
foreach (var value in obj.Value)
{
Console.WriteLine($"Name: 'Name' Value: {value.Name}");
Console.WriteLine($"Name: 'CustomerAccount' Value: {value.CustomerAccount}");
}
}
}
If you don't know the keys (properties are dynamic) of the object, you could use the following code snippet but it needs a change in the class declaration.
class Customer
{
//this is list of value objects (value is a dictionary)
public List<Dictionary<String,String>> Value { get; set; }
}
And here's how to deserialize and loop through the array of values
var obj = JsonConvert.DeserializeObject<Customer>(myString);
foreach (var value in obj.Value)
{
foreach (var key in value)
{
if (key.Key == "#odata.etag")
continue;
Console.WriteLine("Name: [{0}], Value: [{1}]",key.Key, key.Value);
}
}

C# Deserialize JSON Response

I've written a csharp app which queries our load balancers (which are setup in an active/passive configuration) to determine which is the active. The load balancers have a REST API which I'm querying as such:
public void GetActiveLB()
{
// Create a new RestClient and RestRequest
var client = new RestClient("https://myloadbalancer.domain.local");
var request = new RestRequest("mgmt/tm/cm/failover-status", Method.GET);
// Specify authentication
client.Authenticator = new HttpBasicAuthenticator("myusername", "supersecret");
// ask for the response to be in JSON syntax
request.RequestFormat = DataFormat.Json;
//send the request to the web service and store the response when it comes back
var queryResult = client.Execute(request);
// Create a new Deserializer to be able to parse the JSON object
RestSharp.Deserializers.JsonDeserializer deserial = new JsonDeserializer();
var JSONObj = deserial.Deserialize<Dictionary<string, string>>(queryResult);
string lbstatus = JSONObj["description"];
}
The JSON returned to me looks like this:
{
"kind":"tm:cm:failover-status:failover-statusstats",
"selfLink":"https://localhost/mgmt/tm/cm/failover-status?ver=11.6.0",
"entries": {
"https://localhost/mgmt/tm/cm/failover-status/0": {
"nestedStats": {
"entries": {
"color": {
"description": "green"
},
"https://localhost/mgmt/tm/cm/failoverStatus/0/details": {
"nestedStats": {
"entries": {
"https://localhost/mgmt/tm/cm/failoverStatus/0/details/0": {
"nestedStats": {
"entries": {
"details": {
"description": "active for /Common/traffic-group-1"
}
}
}
}
}
}
},
"status": {
"description": "ACTIVE"
},
"summary": {
"description": "1/1 active"
}
}
}
}
}}
Here's a prettier formatted version:)
The path to the item I want is:
[JSON].entries.https://localhost/mgmt/tm/cm/failover-status/0.nestedStats.entries.status.description
What I am struggling with is how to get the value of this item particularly because it seems to be nested multiple times. Is there a way to provide an absolute path?
Thank You
Brad
If the json is always structured the same way you can create some poco's that nest themselves and then deserialise with the json deserialisation:
eg:
[DataContract]
public class JsonResponse
{
[datamember]
public string kind;
[datamember]
public string selflink;
[datamember]
public Entry entries; //we nest another object here just as in the json
}
[DataContract]
public class Entry
{
[datamember]
public nestedstat nestedstats;
}
(this is just loosly typed)
then:
JsonResponse response = new JavaScriptSerializer().Deserialize<JsonResponse>(jsonasstring);
The easiest way to do it is to use the dynamic keyword like this:
dynamic JSONObj =
deserial
.Deserialize<Dictionary<string, object>>(queryResult); //Notice how I am using Dictionary<string, object> instead of Dictionary<string, string> since some of the values are actually parents of other values so they will be presented as dictionaries themselves.
var lbstatus =
JSONObj
["entries"]
["https://localhost/mgmt/tm/cm/failover-status/0"]
["nestedStats"]
["entries"]
["status"]
["description"];
If you don't use the dynamic keyword then you would have to cast JSONObj["entries"] into a Dictionary<string,object>, and then when you access ["https://localhost/mgmt/tm/cm/failover-status/0"] on that dictionary, you would need to cast the result again into Dictionary<string,object> ... etc.
In this case, the dynamic keyword will make it very much easier.
If you want to get the result from an absolute path, you can do something like this with dynamic:
dynamic JSONObj = deserial.Deserialize<Dictionary<string, object>>(queryResult);
string path =
"entries.https://localhost/mgmt/tm/cm/failover-status/0.nestedStats.entries.status.description";
dynamic value = JSONObj;
foreach (var sub_path in path.Split('.'))
{
value = value[sub_path];
}
var lbstatus = value.ToString();

Using JArray for serializing data from database in WebAPI (C#)

I want to achieve the following JSON data:
[
{
"name":"Deutschland",
"code":"de"
},
{
"name":"Frankreich",
"code":"fr"
},
{
"name":"Japan",
"code":"jpn"
}
]
Currently I'm getting this result of JSON data:
{
"groups":[
{
"name":"Deutschland",
"code":"de"
},
{
"name":"Frankreich",
"code":"fr"
},
{
"name":"Japan",
"code":"jpn"
}
]
}
Here is the code of the Controller:
public dynamic GetGroups()
{
JObject o = JObject.FromObject(new
{
groups = from g in db.QR_Groups
select new
{
name = g.name,
code = g.code
}
});
return o;
/*Here I've tried to get JSON data as array without the Property "groups"*/
//JArray a = new JArray(
// from g in db.QR_Groups
// select new JValue(g));
//return a;
}
Can anyone tell me how to retrieve the JSON data as per the first JSON example above?
And is the type "dynamic" good practice for the method?
First of all there is no need to do serialization manually. ASP.Net WebApi MediaFormatters are going to take care of it based on the Request Content-Type. So Create a class as shown below.
public class Group
{
public string name { get; set; }
public string code { get; set; }
}
Then your Web API endpoint should be -
[HttpGet]
public HttpResponseMessage GetCountries()
{
List<Group> groups = (from g in db.QR_Groups
select new Group
{
name = g.name,
code = g.code
}).ToList();
return Request.CreateResponse(HttpStatusCode.OK, groups);
}
And when I make a Fiddler request, I was able to get the output which you are interested -
Try this one:
var json = JsonConvert.SerializeObject(from g in db.QR_Groups
select new
{
name = g.name,
code = g.code
});
And is the type "dynamic" good practice for the method?
no, it's not best practise. Better one is to create new class

C# DataContractJsonSerializer fails when value can be an array or a single item

I use the DataContractJsonSerializer to parse a json string into a object hierarchie.
The json string looks like this:
{
"groups": [
{
"attributes": [
{
"sortOrder": "1",
"value": "A"
},
{
"sortOrder": "2",
"value": "B"
}
]
},
{
"attributes": {
"sortOrder": "1",
"value": "C"
}
}
]
}
As you can see the sub value of "attributes" can be an array or a single item.
I found the code part where the problem occures:
[DataContract]
public class ItemGroup
{
[DataMember(Name="attributes")]
public List<DetailItem> Items { get; set; }
}
This works for the first one but fails on the second one.
Has anyone an answer for this?
Thx
If you control how the JSON is created then make sure that attributes is an array even if it only contains one element. Then the second element will look like this and parse fine.
{
"attributes": [{
"sortOrder": "1",
"value": "C"
}]
}
As Daniel said, if you can control the creation of Json, it is better to continue that way.
But if you can't, then you can use Json.Net library & the JsonObject class from
this link to write some code like:
JObject o = (JObject)JsonConvert.DeserializeObject(input);
dynamic json = new JsonObject(o);
foreach (var x in json.groups)
{
var attrs = x.attributes;
if (attrs is JArray)
{
foreach (var y in attrs)
{
Console.WriteLine(y.value);
}
}
else
{
Console.WriteLine(attrs.value);
}
}
I tried to get this working with DataContractJsonSerializer, JavaScriptSerializer, and JSON.Net and none would deserialize directly to an object successfully in all cases. I used a similar approach as L.B, using JSON.Net, although without the use of dynamics and the extra JsonObject class. Adapting my code to your scenario would look something like the following:
private List<ItemGroup> ParseItemGroupList(string input)
{
JObject json = JObject.Parse(input);
List<ItemGroup> groups = new List<ItemGroup>();
JArray gArray = json["groups"] as JArray;
foreach (var gToken in gArray)
{
ItemGroup newGroup = new ItemGroup();
JToken attrToken = gToken["attributes"] as JToken;
if (attrToken is JArray)
{
newGroup.Items = attrToken.Children().Select(MapDetailItem()).ToList();
}
else
{
newGroup.Items = new List<DetailItem>() { MapDetailItem().Invoke(attrToken) };
}
groups.Add(newGroup);
}
return groups;
}
private static Func<JToken, DetailItem> MapDetailItem()
{
return json => new DetailItem
{
SortOrder = (string)json["sortOrder"],
Value = (string)json["value"]
};
}
Hopefully, someone will add a setting for JSON.Net to allow it to force deserialization to a collection with a single item rather than throwing an exception. It's a shame that you have to do all of the parsing manually when there is only one small portion of the JSON that doesn't parse correctly automatically.

Categories