I am getting this 'optimized' JSON response from a third party web service presented as follows, I built the type as per the information presented in the keys but the difficulty I am facing is that data is not represented in objects but in arrays, is there a way to automate the building and value mapping of my objects list?
{
"reports": {
"query": {
"keys": [{
"name": "Date",
"type": "date"
}, {
"name": "NetSales",
"type": "price"
}, {
"name": "GrossCash",
"type": "price"
}, {
"name": "GrossCard",
"type": "price"
}, {
"name": "GrossDelivery",
"type": "price"
}, {
"name": "NetFood",
"type": "price"
}, {
"name": "NetDrink",
"type": "price"
}, {
"name": "NetRetail",
"type": "price"
}, {
"name": "Baskets",
"type": "int"
}],
"data": [
[1523577600000, 51924, 11300, 27200, 9900, null, null, null, 8],
[1523404800000, 7434, 2600, 3900, null, null, null, null, 6],
[1523491200000, 18101, 4000, 10100, null, null, null, null, 5],
[1523664000000, 13243, 7400, 6500, null, null, null, null, 3],
[1523750400000, 11718, 7300, null, 5000, null, null, null, 2],
[1523836800000, 16576, 7700, 4800, 4900, null, null, null, 4],
[1524096000000, 20293, 9100, 6000, null, null, null, null, 4]
]
}
},
"api": {
"message": {
"success": {
"202": {
"id": 202,
"title": "Token is valid",
"details": "Token is validated and found valid."
}
}
},
"codeBaseVersion": 1,
"executionTime_milliSeconds": 43
}
}
I ended up with this code but not satisfied with it:
JObject myOpject = JObject.Parse(responseString);
List<JToken> setOfObjects = myOpject["reports"]["query"]["data"].Children().ToList();
var listOfData = new List<Data2>();
foreach (var token in setOfObjects)
{
var myObject = new Data2
{
NetSales = decimal.Parse(token[1].ToString()),
//etc.
};
listOfData.Add(myObject);
}
using the same JToken idea transform the data using the keys to create a new object model and then deserialize that to the strong type desired.
For example, taking a few records you can transform the keys and data to
[
{
"Date": 1523577600000,
"NetSales": 51924,
...
},
{
"Date": 1523404800000,
"NetSales": 7434,
...
},
...
]
The following code attempts to build that using the key index matched to the index of item in data array
JObject myOpject = JObject.Parse(responseString);
List<JToken> keys = myOpject["reports"]["query"]["keys"].Children().ToList();
List<JToken> data = myOpject["reports"]["query"]["data"].Children().ToList();
var array = new JArray();
foreach (var token in data) {
var record = new JObject();
for (var i = 0; i < keys.Count; i++) {
var propertyName = keys[i]["name"].Value<string>();
var propertyValue = token[i];
record[propertyName] = propertyValue;
}
array.Add(record);
}
var listOfData = array.ToObject<List<Data2>>(); // or Data2[], etc
assuming Data2 is your strongly typed model with matching properties.
Related
I'm looking for a way to find a specific json value by its name and set its value to null. The construction of the json file can be anything, it's not always the same.
Let's say the json looks like this:
[
{
"id": "1111",
"email": "email#email.com",
},
{
"id": "2222",
"email": "email2#email2.com",
}]
The result I'm looking for is this:
[
{
"id": "1111",
"email": null,
},
{
"id": "2222",
"email": null,
}]
When the object is more complicated it should work too.
{
"reservations": [
{
"id": "111",
"bookingId": "",
"status": "",
"checkInTime": "",
"checkOutTime": "",
"property": {
"id": "",
"code": "",
"name": "",
},
"primaryGuest": {
"firstName": "",
"middleInitial": "",
"lastName": "",
"email": "email#email.com",
"phone": "",
"address": {
"addressLine1": "",
"postalCode": "",
"city": "",
"countryCode": ""
}
},
"booker": {
"firstName": "",
"middleInitial": "",
"lastName": "",
"email": "email2#email.com",
"phone": ""
}
}]}
I've tried to use JArray, JObject classes etc, but it only works if the propety["email"] is the first child, not deeper. Not sure how to accomplish this.
private JObject HashSensitiveData(JContainer jContainer)
{
if (!jContainer.Descendants().Any())
{
return null;
}
var objects = jContainer.Descendants().OfType<JObject>();
foreach (var property in objects)
{
foreach (var emailProperty in property.Properties().Where(x => x.Name.CaseInsensitiveContains(LoggerHashedProperties.Email.ToString())))
{
var email = emailProperty.Value.ToString();
property[emailProperty.Name] =null
}
}
return HashSensitiveData(jContainer);
}
Using NewtonSoft, I once made a flatten function to analyse json files of any depth:
IEnumerable<JProperty> Flatten(JToken token)
{
return token.Children<JProperty>().Concat(
token.Children().SelectMany(t => Flatten(t)))
.Where(t => t.Value is JValue);
}
It returns a flat listing of all "endpoint" JsonPropertys in a file (say: all "xyx" : primitive value entries). Using it you can simply deserialize your Json, find all "email" properties and set their value to null:
var jobj = JsonConvert.DeserializeObject<JObject>(getJson());
var flattened = Flatten(jobj);
foreach (var jprop in flattened.Where(t => t.Name == "email"))
{
jprop.Value = null;
}
var json = JsonConvert.SerializeObject(jobj).Dump();
Result for the "more complicated" json (with one deeper email added to make it more fun):
{
"reservations": [
{
"id": "111",
"bookingId": "",
"status": "",
"checkInTime": "",
"checkOutTime": "",
"property": {
"id": "",
"code": "",
"name": ""
},
"primaryGuest": {
"firstName": "",
"middleInitial": "",
"lastName": "",
"email": null,
"phone": "",
"address": {
"email": null,
"addressLine1": "",
"postalCode": "",
"city": "",
"countryCode": ""
}
},
"booker": {
"firstName": "",
"middleInitial": "",
"lastName": "",
"email": null,
"phone": ""
}
}
]
}
With System.Text.Json and Utf8JsonWriter you can process and write your JSON recursively:
public static void RemoveContent(JsonElement element, Utf8JsonWriter writer)
{
// Current element is an array, so we have to iterate over all elements.
if (element.ValueKind == JsonValueKind.Array)
{
writer.WriteStartArray();
foreach (var e in element.EnumerateArray())
{
RemoveContent(e, writer);
}
writer.WriteEndArray();
}
// Current element is an object, so we have to process all properties.
else if (element.ValueKind == JsonValueKind.Object)
{
writer.WriteStartObject();
foreach (var e in element.EnumerateObject())
{
writer.WritePropertyName(e.Name);
// * Process specific elements. ************************************************
if (e.Name == "email") { writer.WriteNullValue(); }
else RemoveContent(e.Value, writer);
}
writer.WriteEndObject();
}
// We are at the leaf (a string property, ...) and we write this as it is.
else
{
element.WriteTo(writer);
}
}
Usage:
using var stream = new MemoryStream();
// We have to flush writer before reading it's content.
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { SkipValidation = true }))
{
var element = JsonDocument.Parse(jsonStr).RootElement;
RemoveContent(element, writer);
}
// Stream contains a byte array with UTF-8 content.
// If you want a string, you can use UTF8 decoding.
var json = System.Text.Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(json);
I have a Json file with couple of fields and I have some problems searching for specific fields.
This is the Json file(I cut it short since the original is huge):
{
"errors": {
"errorCode": 0,
"errorMessage": "",
"errorDescription": null
},
"pagination": {
"recordsReturned": 250,
"totalRecordsFound": 123,
"currentPage": 1,
"recordsPerPage": 250
},
"data": {
"totalDCount": 1713,
"totalValue": "50",
"totalCarats": 60,
"averagePricePerCarat": 21,
"averageDiscount": -0.29,
"dResult": [
{
"color": "H",
"dID": 4693,
"fancyColor": {
"dominantColor": null,
"secondaryColor": null,
"overtones": null,
"intensity": null,
"color1": null,
"color2": null
},
"seller": {
"accountID": 124,
"companyName": "",
"companyCode": " ",
"founded": "",
"address": null,
"telephone": " ",
"fax": null,
"email": null,
"contactPrimaryName": "value",
"city": null,
"state": null,
"country": "USA",
"address1": null,
"address2": null,
"skypeName": null,
"primarySupplierBadge": true,
"ratingPercent": 1.0,
"totalRating": 1.0,
"relatedAccounts": null
},
"shape": "Round",
{
"color": "H",
"dID": 46,
"fancyColor": {
"dominantColor": null,
"secondaryColor": null,
"overtones": null,
"intensity": null,
"color1": null,
"color2": null
},
"seller": {
"accountID": 124,
"companyName": "",
"companyCode": " ",
"founded": "",
"address": null,
"telephone": " ",
"fax": null,
"email": null,
"contactPrimaryName": "value",
"city": null,
"state": null,
"country": "USA",
"address1": null,
"address2": null,
"skypeName": null,
"primarySupplierBadge": true,
"ratingPercent": 1.0,
"totalRating": 1.0,
"relatedAccounts": null
},
"shape": "Round"
}
]
}
}
I wrote a code that should search for "dId" field value under the "dResult". Unfortunately this error comes up (I am using Newtonsoft.Json parser) :
"Newtonsoft.Json.JsonReaderException: Invalid property identifier character: {. Path 'data.dResult[0].shape', line 54, position 11."
A.This is the code I wrote, I would be happy if you could tell me what is the problem ?
B.A second problem that I had is that I need to pick only the "dID" of those that have the "shape" field value as "Round", I didn't figure out a way to do that since I need to go and find a further field while encountering "dId" field .
class Program
{
static void Main(string[] args)
{
string filepath = "../../json1.json";
string result = string.Empty;
string str = string.Empty;
using (StreamReader r = new StreamReader(filepath))
{
var json = r.ReadToEnd();
JObject jObject = JObject.Parse(json);
JToken jUser = jObject["data"];
string jsonString = jUser.ToString();
JObject jObject1 = JObject.Parse(jsonString);
JToken jUser2 = jObject1["dResult"];
string jsonString2 = jUser2.ToString();
JObject jObject2 = JObject.Parse(jsonString2);
foreach (var item in jObject2.Properties())
{
if (item.Name == "dID")
{
str = item.Value.ToString();
result = result + " " + str;
}
}
}
Console.WriteLine(result);
}
}
Reference for the comment I received here (Another Json section, this is under "dResult"):
, {
"dID": 281242,
"seller": {
"accountID": 21321,
"companyName": "RA",
"companyCode": "001",
"founded": "000",
"address": null,
"telephone": "999",
"fax": null,
"email": null,
"contactPrimaryName": "name",
"city": null,
"state": null,
"country": "USA",
"address1": null,
"address2": null,
"skypeName": null,
"primarySupplierBadge": true,
"ratingPercent": 1.0,
"totalRating": 1.0,
"relatedAccounts": null
},
"shape": "Round",
"size": 0.010,
"color": "K",
"fancyColor": {
"dominantColor": null,
"secondaryColor": null,
"overtones": null,
"intensity": null,
"color1": null,
"color2": null
},
You can use the following Linq query to pull the dID values for the Round shapes. However the JSON is not in a correct format.
var jsonStr = File.ReadAllText(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
"example-json.json"));
var parsed = JObject.Parse(jsonStr);
var dIdList = parsed["data"]["dResult"]
.Where(x => x.Value<String>("shape").Equals("round", StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.Value<Int32>("dID"))
.ToList();
And here is the re-formatted JSON (notice the diff on line 52-53), there was a missing } which caused the array to be off:
Once you correct the JSON, by adding this } and run the above Linq query it will return the following result:
Good, luck. Let me know if you need any further assistance.
Once you fix the improperly formatted json data, you can use linq to find the round objects:
var searchResults = from r in jObject["data"]["dResult"]
where r["shape"].ToString() == "Round"
select r;
foreach (var r in searchResults)
{
Console.WriteLine(r["dID"]);
}
I am using the LiveConnect sdk to get some user info.
After doing whatever is necessary for that, this is the result I'm getting:
{
"id": "123456789",
"name": "a b",
"first_name": "a",
"last_name": "b",
"link": "https://profile.live.com/",
"work": [],
"gender": null,
"emails": {
"preferred": "a#live.com",
"account": "a#live.com",
"personal": null,
"business": null
},
"addresses": {
"personal": {
"street": null,
"street_2": null,
"city": null,
"state": null,
"postal_code": null,
"region": null
},
"business": {
"street": null,
"street_2": null,
"city": null,
"state": null,
"postal_code": null,
"region": null
}
},
"locale": "en_US",
"updated_time": "2013-10-10T08:41:14+0000"
}
I need to get the "account" inside "emails".
First, when I got this string I did the following:
public Dictionary<string, object> userData = new Dictionary<string, object>();
userData = deserializeJsonObject(<the string above>);
private Dictionary<string, object> deserializeJsonObject(string json)
{
var jss = new JavaScriptSerializer();
var d = jss.Deserialize<Dictionary<string, object>>(json);
return d;
}
Now, in order to get the account email, I was going to do something like:
string email = userData["emails"]["account"];
but since this is a string, object dictionary, I get an error that it's not possible because userData["emails"] is an object.
How can I get the data?
do you had tried to make a cast?
for example:
(userData["emails"] as Dictionary<string,object>)["account"]
or:
((Dictionary<string,object>)userData["emails"])["account"]
I'm currently stuck on JSON deserialization.
Here is two type of JSON, I can receive :
{
"code": 0,
"response": {
"isFollowing": false,
"isFollowedBy": false,
"connections": {
"google": {
"url": "",
"id": "c35f4e",
"name": "jean"
},
"facebook": {
"url": "https://www.facebook.com/",
"id": "1000064139",
"name": "jean mic"
}
},
"isPrimary": true,
"id": "780",
"location": "",
"isPrivate": false,
"joinedAt": "2013-10-18T16:04:09",
"username": "jeandavid",
"numLikesReceived": 0,
"about": "",
"name": "jean",
"url": "",
"profileUrl": "",
"reputation": ,
"avatar": {
"small": {
"permalink": "https://picture.jpg",
"cache": "https://picture.jpg"
},
"isCustom": false,
"permalink": "https://picture.jpg",
"cache": "/noavatar9.png",
"large": {
"permalink": "w",
"cache": "https://picture.jpg"
}
},
"isAnonymous": false
}
}
And this one :
{
"response": [
{
"uid": 2017156,
"first_name": "David",
"last_name": "Jean",
"sex": 1,
"nickname": "",
"bdate": "12.12.1990",
"photo_medium": "img.jpg"
}
]
}
At beginning, I use :
Dictionary<string, string> deserializedObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
But it works only with unidimensional Json data.
So after looking on Google, I tried to use :
JArray jArr = (JArray)JsonConvert.DeserializeObject(response);
foreach (var item in jArr)
{
Console.WriteLine(item);
}
But I receive this exception :
Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'.
For the first JSON data I would like to get the Google and Facebook data and also the username, the reputation, the avatar, the id of the user, ...
Thanks for any help!!
I have the following Json gotten from Twitter
+ token {[
{
"trends": [
{
"name": "Croke Park II",
"url": "http://twitter.com/search?q=%22Croke+Park+II%22",
"promoted_content": null,
"query": "%22Croke+Park+II%22",
"events": null
},
{
"name": "#twiznight",
"url": "http://twitter.com/search?q=%23twiznight",
"promoted_content": null,
"query": "%23twiznight",
"events": null
},
{
"name": "#Phanhattan",
"url": "http://twitter.com/search?q=%23Phanhattan",
"promoted_content": null,
"query": "%23Phanhattan",
"events": null
},
{
"name": "#VinB",
"url": "http://twitter.com/search?q=%23VinB",
"promoted_content": null,
"query": "%23VinB",
"events": null
},
{
"name": "#Boston",
"url": "http://twitter.com/search?q=%23Boston",
"promoted_content": null,
"query": "%23Boston",
"events": null
},
{
"name": "#rtept",
"url": "http://twitter.com/search?q=%23rtept",
"promoted_content": null,
"query": "%23rtept",
"events": null
},
{
"name": "Facebook",
"url": "http://twitter.com/search?q=Facebook",
"promoted_content": null,
"query": "Facebook",
"events": null
},
{
"name": "Ireland",
"url": "http://twitter.com/search?q=Ireland",
"promoted_content": null,
"query": "Ireland",
"events": null
},
{
"name": "Everton",
"url": "http://twitter.com/search?q=Everton",
"promoted_content": null,
"query": "Everton",
"events": null
},
{
"name": "Twitter",
"url": "http://twitter.com/search?q=Twitter",
"promoted_content": null,
"query": "Twitter",
"events": null
}
],
"as_of": "2013-04-17T13:05:30Z",
"created_at": "2013-04-17T12:51:41Z",
"locations": [
{
"name": "Dublin",
"woeid": 560743
}
]
}
]} Newtonsoft.Json.Linq.JToken {Newtonsoft.Json.Linq.JArray}
Problem is I can't seem to access any of the elements. I have tried foreach loops and normal for loops and can never seem to access individual elemets it always ends up accessing the whole area.
Any idea how I access the individual elements in this Json JArray?
There is a much simpler solution for that.
Just treat the items of the JArray as JObject.
Let's say we have such array of JSON objects:
JArray jArray = JArray.Parse(#"[
{
""name"": ""Croke Park II"",
""url"": ""http://twitter.com/search?q=%22Croke+Park+II%22"",
""promoted_content"": null,
""query"": ""%22Croke+Park+II%22"",
""events"": null
},
{
""name"": ""Siptu"",
""url"": ""http://twitter.com/search?q=Siptu"",
""promoted_content"": null,
""query"": ""Siptu"",
""events"": null
}]");
To get access each item just do the following:
foreach (JObject item in jArray) // <-- Note that here we used JObject instead of usual JProperty
{
string name = item.GetValue("name").ToString();
string url = item.GetValue("url").ToString();
// ...
}
Update - I verified the below works. Maybe the creation of your JArray isn't quite right.
[TestMethod]
public void TestJson()
{
var jsonString = #"{""trends"": [
{
""name"": ""Croke Park II"",
""url"": ""http://twitter.com/search?q=%22Croke+Park+II%22"",
""promoted_content"": null,
""query"": ""%22Croke+Park+II%22"",
""events"": null
},
{
""name"": ""Siptu"",
""url"": ""http://twitter.com/search?q=Siptu"",
""promoted_content"": null,
""query"": ""Siptu"",
""events"": null
},
{
""name"": ""#HNCJ"",
""url"": ""http://twitter.com/search?q=%23HNCJ"",
""promoted_content"": null,
""query"": ""%23HNCJ"",
""events"": null
},
{
""name"": ""Boston"",
""url"": ""http://twitter.com/search?q=Boston"",
""promoted_content"": null,
""query"": ""Boston"",
""events"": null
},
{
""name"": ""#prayforboston"",
""url"": ""http://twitter.com/search?q=%23prayforboston"",
""promoted_content"": null,
""query"": ""%23prayforboston"",
""events"": null
},
{
""name"": ""#TheMrsCarterShow"",
""url"": ""http://twitter.com/search?q=%23TheMrsCarterShow"",
""promoted_content"": null,
""query"": ""%23TheMrsCarterShow"",
""events"": null
},
{
""name"": ""#Raw"",
""url"": ""http://twitter.com/search?q=%23Raw"",
""promoted_content"": null,
""query"": ""%23Raw"",
""events"": null
},
{
""name"": ""Iran"",
""url"": ""http://twitter.com/search?q=Iran"",
""promoted_content"": null,
""query"": ""Iran"",
""events"": null
},
{
""name"": ""#gaa"",
""url"": ""http://twitter.com/search?q=%23gaa"",
""promoted_content"": null,
""query"": ""gaa"",
""events"": null
},
{
""name"": ""Facebook"",
""url"": ""http://twitter.com/search?q=Facebook"",
""promoted_content"": null,
""query"": ""Facebook"",
""events"": null
}]}";
var twitterObject = JToken.Parse(jsonString);
var trendsArray = twitterObject.Children<JProperty>().FirstOrDefault(x => x.Name == "trends").Value;
foreach (var item in trendsArray.Children())
{
var itemProperties = item.Children<JProperty>();
//you could do a foreach or a linq here depending on what you need to do exactly with the value
var myElement = itemProperties.FirstOrDefault(x => x.Name == "url");
var myElementValue = myElement.Value; ////This is a JValue type
}
}
So call Children on your JArray to get each JObject in JArray. Call Children on each JObject to access the objects properties.
foreach(var item in yourJArray.Children())
{
var itemProperties = item.Children<JProperty>();
//you could do a foreach or a linq here depending on what you need to do exactly with the value
var myElement = itemProperties.FirstOrDefault(x => x.Name == "url");
var myElementValue = myElement.Value; ////This is a JValue type
}
Once you have a JArray you can treat it just like any other Enumerable object,
and using linq you can access them, check them, verify them, and select them.
var str = #"[1, 2, 3]";
var jArray = JArray.Parse(str);
Console.WriteLine(String.Join("-", jArray.Where(i => (int)i > 1).Select(i => i.ToString())));
void ConvertToJArray(object headers)
{
//where headers is your Twitter response
JObject JObj = (JObject)headers;//Parse to JObject
JArray JArr = (JArray)JObj["trends"];//Get the trends array as JArray
for (int i = 0; i < JArr.Count; i++)
{
var Name = JArr[i]["name"].ToString();
var URL = JArr[i]["url"].ToString();
}
}