Replace a JSON value of a property in several JObjects - c#

I have a JSON file I'm reading from text and parsing it into JObject using Newtonsoft.Json.Linq. The JSON file looks like this:
{
"EntityTypeDto":[
{
"EntityType":"Grade",
"Language":"ES"
},
{
"EntityType":"ApplicationType",
"Language":"ES"
},
{
"EntityType":"Borough",
"Language":"ES"
}
]
}
Using the Newtonsoft library, are there any methods I can leverage on JObject to replace the Language property of all the objects to another value? If not what would be another way to do this? This project is a console application in C#, VS 2012, thanks.

You don't need Linq here to achieve what you need , Linq is for consult data, not for modify it. So you can just, eg, a foreach to iterate and modify the elements of the array:
JObject json= JObject.Parse(jsonString);
JArray entityTypeDtos= (JArray)json["EntityTypeDto"];
foreach(var e in entityTypeDtos)
{
if(e["Language"] != null)
e["Language"]="EN";
}

I'm guessing by the Linq tag you would like a Linq approach try this
string json = #"{
'EntityTypeDto':[
{
'EntityType':'Grade',
'Language':'ES'
},
{
'EntityType':'ApplicationType',
'Language':'ES'
},
{
'EntityType':'Borough',
'Language':'ES'
}
]
}";
JObject myjobj = JObject.Parse(json);
JArray EntityType = (JArray)myjobj["EntityTypeDto"];
(from eobj in EntityType
where eobj["Language"]="ES"
select eobj).ForEach(x => x["Language"]="New Value");

Related

Moving all properties from a nested JObject to the root

I have the following json format that I need to change by removing the "root" element and then sending it for processing.
{
"deonItemDetails":[
{
"hsDesc":"",
"namePLU":"AGO LOCAL",
"taxRate":0.0,
"unitPrice":71.0,
"discount":0.0,
"hsCode":"",
"quantity":1.0,
"measureUnit":"Litres",
"vatClass":"A"
}
],
"root":{
"senderId":"a4031de9-d11f-4b52-8cca-e1c7422f3c37",
"invoiceCategory":"tax_invoice",
"traderSystemInvoiceNumber":"34058",
"relevantInvoiceNumber":"",
"pinOfBuyer":"P051400323I",
"invoiceType":"Original",
"exemptionNumber":"",
"totalInvoiceAmount":71.0,
"systemUser":"manager"
}
}
I need it to be like this:
{
"deonItemDetails":[
{
"hsDesc":"",
"namePLU":"AGO LOCAL",
"taxRate":0.0,
"unitPrice":71.0,
"discount":0.0,
"hsCode":"",
"quantity":1.0,
"measureUnit":"Litres",
"vatClass":"A"
}
],
"senderId":"a4031de9-d11f-4b52-8cca-e1c7422f3c37",
"invoiceCategory":"tax_invoice",
"traderSystemInvoiceNumber":"34058",
"relevantInvoiceNumber":"",
"pinOfBuyer":"P051400323I",
"invoiceType":"Original",
"exemptionNumber":"",
"totalInvoiceAmount":71.0,
"systemUser":"manager"
}
However, using the following code, all content of root is removed instead of just the tag and brackets belinging to that node.
JObject jo = JObject.Parse(jsonToSendDetails);
jo.Property("root").Remove();
var newjson = jo.ToString();
How do I get the json to look like the 2nd one?
Solution 1
#JonSkeet had explained the concept:
Get the properties in the root.
Add the properties from 1 to the JObject.
Remove the root property from the JObject.
The below code is the implementation:
using Newtonsoft.Json.Linq;
JObject jObj = JObject.Parse(json);
JObject rootObj = (JObject)jObj["root"];
foreach (JProperty prop in rootObj.Properties())
{
jObj.Add(prop.Name, prop.Value);
}
jObj.Remove("root");
Demo Solution 1 # .Net Fiddle
Solution 2
Besides, you may work with JObject.Merge() as well.
using Newtonsoft.Json.Linq;
JObject jObj = JObject.Parse(json);
jObj.Merge(jObj["root"]);
jObj.Remove("root");
Demo Solution 2 # .NET Fiddle
just for the record
var jsonParsed = JObject.Parse(json);
var fixedObj = (JObject)jsonParsed["root"];
//if, most probably, the order of properties doesn't matter
fixedObj["deonItemDetails"] = jsonParsed["deonItemDetails"];
json = fixedObj.ToString();
// or if the order of properties matters
fixedObj.AddFirst( new JProperty("deonItemDetails", jsonParsed["deonItemDetails"]));

C# Unable to modify Json with Newtonsoft

I have a string type variable named final and it contains the following Json:
{
"Game": {
"Player_Decks": {
"1": {
"Card_List": "2_Yellow,1_Blue,Reverse_Green,5_Yellow,5_Red,7_Red,2_Blue",
"Card_Count": 7
},
"2": {
"Card_List": "5_Blue,9_Green,4_Yellow,6_Green,0_Red,2_Green,6_Yellow",
"Card_Count": 7
}
},
"Deck_NoCards": {}
}
}
My code looks like this: (taken from here: https://www.newtonsoft.com/json/help/html/ModifyJson.htm)
JObject rss = JObject.Parse(final);
JObject channel = (JObject)rss["Game.Player_Decks.1"];
channel.Property("Card_Count").AddAfterSelf(new JProperty("new", "New value"));
I want to add another value after Card_Count, but I have a feeling that my string isn't "compatible" or something. What can be done here to fix my problem?
Reposting comment as answer here:
You cannot access the nested object using a dotted path "Game.Player_Decks.1". Instead you need to individually address each property within each object.
JObjects are effectively an array of named properties, JObject implements IDictionary<string, JToken?> so as long as each child element is also a JObject then you can use the string index to reference the element in the next level.
JObject game = (JObject)rss["Game"];
JObject decks = (JObject)game["Player_Decks"];
JObject channel = (JObject)decks["1"];
channel.Property("Card_Count").AddAfterSelf(new JProperty("new", "New value"));
The following syntax should also work:
JObject channel = rss["Game"]["Player_Decks"]["1"] as JObject;
Also, have you considered using a Json Array instead of properties named 1, 2, etc. like so:
{
"Game": {
"Player_Decks": [
{
"Card_List": "2_Yellow,1_Blue,Reverse_Green,5_Yellow,5_Red,7_Red,2_Blue",
"Card_Count": 7
},
{
"Card_List": "5_Blue,9_Green,4_Yellow,6_Green,0_Red,2_Green,6_Yellow",
"Card_Count": 7
}
],
"Deck_NoCards": {}
}
}
and accessed as:
JObject rss = JObject.Parse(final);
JObject game = (JObject)rss["Game"];
JArray decks = (JArray)game["Player_Decks"];
JObject deck1 = (JObject)decks[0];

C# find JSON value based only on Key name through multiple levels of array

I have a variety of input JSON formatted data which all contain a particular key-name terminalSize. This is the only piece I know. The total number of JSON trees or the exact depth of terminalSize inside the JSON tree will forever be an unknown and subject to change.
I'm looking for a C# solution to loop through every child of the JSON string and find terminalSize then fetch the value.
I've tried this with success but it will only work if terminalSize is in the first level of the JSON:
var list = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jsonString);
var dict = list.SelectMany(d => d).ToDictionary(p => p.Key, p => p.Value);
var terminal = dict["terminalSize"];
Example 1.
{
"status": "success",
"data": {
"terminalSize": 3766505.46,
"totalTerminalSize": 3766505.46
},
"message": null
}
Example 2.
{
"lastUpdated": 1588020678,
"terminalData": {
"terminalSize": "451679852",
"totalTerminalSize": "2100000000"
},
"terminalValueSeries": {
"8x7": 2.33,
"8x6": 3.73,
"8x5": 4.49,
"8x4": 3.68,
"8x3": 13998,
"8x2": 274936,
"8x1": 5.09
}
}
Example 3.
{
"terminalSize": "492612346.17",
"terminalStatus": "online"
}
You can parse your JSON to a JToken, then use SelectToken with the recursive descent JsonPath operator .. to get the terminalSize anywhere in the JSON:
var terminalSize = (double?) JToken.Parse(json).SelectToken("$..terminalSize");
Fiddle: https://dotnetfiddle.net/5ziYbP
If there might be multiple terminalSize keys in the JSON, for example if you had an array of terminals, you can use SelectTokens instead and put the terminal sizes into a Dictionary keyed by path:
var sizes = JToken.Parse(json4)
.SelectTokens("$..terminalSize")
.ToDictionary(t => t.Path, t => (double)t);
Fiddle: https://dotnetfiddle.net/ivSM88
You could also use linq and filter the JProperty collection based on JProperty.Name. For example
var result = JObject.Parse(jsonString)
.DescendantsAndSelf()
.OfType<JProperty>()
.Single(x=>x.Name.Equals("terminalSize"))
.Value;
You may parse your JSON into JObject, then recursively go through all properties and sub objects to find a terminalSize value. There is no need to deserialize the entire JSON into specific object
var json = JObject.Parse(jsonString);
var result = GetTerminalSize(json);
double GetTerminalSize(JObject input)
{
foreach (var property in input.Properties())
{
if (property.Name == "terminalSize")
return property.Value.Value<double>();
if (property.Value.Type == JTokenType.Object)
return GetTerminalSize((JObject) property.Value);
//not sure, if the is a need to handle an array
if (property.Value.Type == JTokenType.Array)
foreach (var item in (JArray) property.Value)
return GetTerminalSize((JObject) item);
}
return 0;
}
It returns a correct value for all 3 examples

How take this json path in newtonsoft.json C#

I have been building an application where JSON will be provided from a user API. It should read the data from the JSON using JSONPath and persist the selected portions. I am trying to do this using Json.Net (Newtonsoft). The following JSON is a sample:
{
// other properties here and different structure here
"Data": [
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
},
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
},
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
}
],
// other properties here and different structure here
}
I would like to extract the array presented by the Data property content using JSONPath and convert it to List<Dictionary<string, object>> to manipulate in my application.
In tools like jsonpath.com the following JSONPath query works fine but with Newtonsoft it does not:
// get that json
string content = GetJson();
var jo = JObject.Parse(content);
var jsonPath = "$..Data.*";
var jsonPathResult = jo.SelectTokens(jsonPath, true /* to get error when it is not found */ );
Instead I got the exception:
Property '*' not valid on JArray.
If I do the JSONPath like this:
var jsonPath = "$..Data"; // same for just: "Data"
var jsonPathResult = jo.SelectTokens(jsonPath);
I have to loop on the result with two nested foreach, what I think it is not an elegant solution:
var result = new List<Dictionary<string, object>>();
foreach (var jsonResult in jsonPathResult)
{
foreach (var item in jsonResult)
{
var fields = JsonConvert.DeserializeObject<Dictionary<string, object>>(item.ToString());
// some adjusts on the fields dictionary will be applied here...
result.Add(fields);
}
}
Is there any way to get the result to take a single loop the only the content of Data property?
As shown in JSONPath - XPath for JSON, the syntax for an array element wildcard is [*]. Thus your code should look like:
var jsonPath = "$..Data[*]";
var result = jo.SelectTokens(jsonPath, true /* to get error when it is not found */ )
.Select(o => o.ToObject<Dictionary<string, object>>())
.ToList();
Here I am using JToken.ToObject<T>() to deserialize each array element directly to a Dictionary<string, object>> without re-serializing to a string.
Sample working .Net fiddle.

Removing an element from a JSON response

I have a JSON string from which I want to be able to delete some data.
Below is the JSON response:
{
"ResponseType": "VirtualBill",
"Response": {
"BillHeader": {
"BillId": "7134",
"DocumentId": "MN003_0522060",
"ConversionValue": "1.0000",
"BillType": "Vndr-Actual",
"AccountDescription": "0522060MMMDDYY",
"AccountLastChangeDate": "06/07/2016"
}
},
"Error": null
}
From above JSON response I want to able remove the
"ResponseType": "VirtualBill", part such that it looks like this:
{
"Response": {
"BillHeader": {
"BillId": "7134",
"DocumentId": "MN003_0522060",
"ConversionValue": "1.0000",
"BillType": "Vndr-Actual",
"AccountDescription": "0522060MMMDDYY",
"AccountLastChangeDate": "06/07/2016"
}
},
"Error": null
}
Is there an easy way to do this in C#?
Using Json.Net, you can remove the unwanted property like this:
JObject jo = JObject.Parse(json);
jo.Property("ResponseType").Remove();
json = jo.ToString();
Fiddle: https://dotnetfiddle.net/BgMQAE
If the property you want to remove is nested inside another object, then you just need to navigate to that object using SelectToken and then Remove the unwanted property from there.
For example, let's say that you wanted to remove the ConversionValue property, which is nested inside BillHeader, which is itself nested inside Response. You can do it like this:
JObject jo = JObject.Parse(json);
JObject header = (JObject)jo.SelectToken("Response.BillHeader");
header.Property("ConversionValue").Remove();
json = jo.ToString();
Fiddle: https://dotnetfiddle.net/hTlbrt
Convert it to a JsonObject, remove the key, and convert it back to string.
Sample sample= new Sample();
var properties=sample.GetType().GetProperties().Where(x=>x.Name!="ResponseType");
var response = new Dictionary<string,object>() ;
foreach(var prop in properties)
{
var propname = prop.Name;
response[propname] = prop.GetValue(sample); ;
}
var response= Newtonsoft.Json.JsonConvert.SerializeObject(response);

Categories