Update specific value in JSON file - c#

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);

Related

Remove Objects items from a list that are in another other two lists

I'm new to C#, and I'm updating to mess with lists.
I currently have this event Object.
From it, I need to generate a new String list.
I must remove all emails that are on Data3 and that are on Data1 and Data2.
{
"event":
{
"userData": [
{
"Data1": [
{
"comentario": "",
"email": "erick#gmail.com",
"name": "erick"
},
{
"comentario": "",
"email": "isa#gmail.com",
"name": "isa"
}
],
"Data2": [
{
"comentario": "",
"email": "erick#gmail.com",
"name": "erick"
}
],
"Data3": [
{
"comentario": "",
"email": "erick#gmail.com",
"name": "erick"
},
{
"comentario": "",
"email": "joseph#gmail.com",
"name": "joseph"
},
{
"comentario": "",
"email": "ju#gmail.com",
"name": "ju"
},
{
"comentario": "",
"email": "isa#gmail.com",
"name": "isa"
}
]
}
]
}
}
The end result would be this:
Newlist = ["joseph#gmail.com", "ju#gmail.com"]
As "erick#gmail.com" and "isa#gmail.com" are in Data1 and Data2, I should remove both from Data3, and return only the others.
If you want to exclude elements from a list that are found in another list just use
var result= list1.Except(list2);
You can use Enumerable.Except method as mentioned in previous answer. A complete example is given below:
List<String> list1 = new List<string>();
list1.Add("Apple");
list1.Add("Ball");
list1.Add("Car");
List<String> list2 = new List<string>();
list2.Add("Cat");
list2.Add("Dog");
list2.Add("Mouse");
list2.Add("Ball");
List<String> newList = list2.Except(list1).ToList();//don't forget to parse new list

How to get all value of particular key in JSON?

I have a JSON structure that contains different levels. How to iterate the JSON and get all values of a particular key in JSON in C#
Below is my JSON file
{
"name": "EPM Company",
"id": "kpfwzgmhpm",
"type": "root",
"childern": [
{
"cid": "67",
"cname": "cname1",
"childern": [
{
"reading": [
{
"id": 121,
"name": "test1"
},
{
"id": 1121,
"name": "test11"
}
]
}
]
},
{
"cid": "454",
"cname": "cname14",
"childern": [
{
"reading": [
{
"id": 454,
"name": "test14"
},
{
"id": 21,
"name": "test141"
}
]
}
]
}
]
}
This is the JSON format. I am trying to get the value in the below format.
{
"name": "EPM Company",
"id": "kpfwzgmhpm",
"value": [
{
"id": 121,
"name": "test1",
"cid": "67",
"cname": "cname1"
},
{
"id": 1121,
"name": "test11",
"cid": "67",
"cname": "cname1"
},
{
"id": 124234,
"cname": "test12342",
"cid": "67",
"name": "cname1"
},
{
"id": 454,
"name": "test14",
"cid": "454",
"cname": "cname14"
},
{
"id": 21,
"name": "test141",
"cid": "454",
"cname": "cname14"
},
{
"id": 121,
"name": "test123122",
"cid": "454",
"cname": "cname14"
}
]
}
fetching all the reading key and its value-added to array with its cid and came. is it possible?
advanced thanks for the help
my code in c# is
public string SensorList(string entireData)
{
if (string.IsNullOrEmpty(entireData))
{
return string.Empty;
}
var returnObj = new Jobject ();
JObject o = JObject.Parse(entireData);
var childern = o["children"];
returnObj.Add("name" = o ["name"];
returnObj.Add("id" = o ["id"];
returnObj.Add("value" = o ["value"];
var valuearry = new JArray();
foreach(var data in childern)
{
foreach(var reading in data["reading"])
{
var valobj = new Jobject ();
valobj.Add( "cid",data["id"])
valobj.Add( "cname",data["name"])
valobj.Add( "name",reading["id"])
valobj.Add( "id",reading["name"])
valuearry.add()
if(data.containsKey("children"))
{
var sensorInfo = SensorList(data["children"]);
}
}
returnObj.Add("value",valuearry);
// var output = sensorInfo.SelectMany(x => ((JObject)x).Properties().Select(y => new JObject {
// new JProperty("id",y.Name),
// new JProperty("name",y.Value["name"])
// })).ToList();
// var returnArray = new JArray(output);
return returnObj.ToString();
}
}
recurring part is not working and take too much time for other long JSON file

Searching for fields in a Json file in C#

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"]);
}

How to safely deserialize keys/data format JSON response

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.

Deserialize a multidimensional Json response

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!!

Categories