Add a list in an existing JSON value - c#

So I have below call to a method where my argument is a json string of this type
var jsonWithSearchData = await querySearchData(jsonOut);
jsonOut ->
[
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": "",
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
]
The querySearchData() returns me two list something like this :["P123","P124","P987"] and ["Ba123","KO817","Daaa112"]
I want to add this list in my r:searchData key above. The key inside my searchData i.e. r:Porelation and ClassA and ClassB remains static. So I would like my searchData in my input Json to finally become something like this.
"r:searchData": {
"r:Porelation":{
"ClassA": ["P123","P124","P987"],
"ClassB": ["Ba123","KO817","Daaa112"]
}
},
How can I do this? What I tried:
JArray jfinObject = JArray.Parse(jobjects);
jfinObject["r:searchData"]["r:relations"]["ClassA"] = JArray.Parse(ListofCode.ToString());
And I get below error:
System.Private.CoreLib: Exception while executing function: Function1.
Newtonsoft.Json: Accessed JArray values with invalid key value:
"r:searchData". Int32 array index expected.

There are a few ways you can add a node/object/array to existing json.
One option is to use Linq-to-Json to build up the correct model.
Assuming you have the json string described in your question, the below code will add your desired json to the r:searchData node:
var arr = JArray.Parse(json); // the json string
var payloadNode = arr[0]["data"]["payload"];
// use linq-to-json to create the correct object
var objectToAdd = new JObject(
new JProperty("r:Porelation",
new JObject(
new JProperty("r:ClassA", array1),
new JProperty("r:ClassB", array2))));
payloadNode["r:searchData"] = objectToAdd;
where array1 and array2 above could come from a linq query (or just standard arrays).
// Output:
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": {
"r:Porelation": {
"r:ClassA": [
"P123",
"P456"
],
"r:ClassB": [
"Ba123",
"Ba456"
]
}
},
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
Online demo
Another option is to create the json from an object, which could be achieved using JToken.FromObject(). However, this will only work if you have property names which are also valid for C# properties. So, this won't work for your desired property names as they contain invalid characters for C# properties, but it might help someone else:
// create JToken with required data using anonymous type
var porelation = JToken.FromObject(new
{
ClassA = new[] { "P123", "P456" }, // replace with your arrays here
ClassB = new[] { "Ba123", "Ba456" } // and here
});
// create JObject and add to original array
var newObjectToAdd = new JObject(new JProperty("r:Porelation", porelation));
payloadNode["r:searchData"] = newObjectToAdd;

Related

C# dynamic object, modify properties based on string paths

The use case is pretty simple in concept. I receive a json payload that has two properties on the root level:
instructions
base
Instructions are set of instructions that I am supposed to apply on the base json object.
For eg - according to the below payload,
I am supposed to traverse to the widgets within defaultWidgets of the base property.
Then replace it completely with whatever is the value of patchedValue.
Input Payload:
{
"instructions": [
{
"patchedPath": "defaultWidget.widgets",
"patchedValue": false,
}
],
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": [
{
"managerId": "defaultWidget",
"widgetId": "invCreateWid7",
"type": "standard",
"manifestPath": "nexxe.standard-section#0.0.0-next.11",
"defaultInputManifestPath": "nexxe.input#0.0.1-alpha.49",
"title": "scannedInvoice",
"children": [
{
"name": "tom"
}
],
"hash": "ktocle2lrgps9",
"directives": ""
}
]
}
}
}
The result should be :
{
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": false
}
}
}
Code:
var stringPayload = "{ \"instructions\": [ { \"patchedPath\": \"defaultWidget.widgets\", \"patchedValue\": false, } ], \"base\": { \"defaultWidget\": { \"hash\": \"ktocle2l0u527\", \"layout\": \"6|6\", \"managerId\": \"defaultWidget\", \"widgets\": [ { \"managerId\": \"defaultWidget\", \"widgetId\": \"invCreateWid7\", \"type\": \"standard\", \"manifestPath\": \"nexxe.standard-section#0.0.0-next.11\", \"defaultInputManifestPath\": \"nexxe.input#0.0.1-alpha.49\", \"title\": \"scannedInvoice\", \"children\": [ { \"name\": \"tom\" } ], \"hash\": \"ktocle2lrgps9\", \"directives\": \"\" } ] } }}";
var parsedPayload = JsonConvert.DeserializeObject(stringPayload);
var baseJ = parsedPayload.GetType().GetProperty("instructions").GetValue(parsedPayload, null);
string jsonString = JsonConvert.SerializeObject(parsedPayload);
I am stuck on the very initial steps , I am getting:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Type.GetProperty(...) returned null.
This is what QuickWatch says:
What's returned by DeserializeObject in this case is JObject so to start with you can cast to it:
var parsedPayload = (JObject) JsonConvert.DeserializeObject(stringPayload);
Then grab instructions and target to change:
var instructions = (JArray) parsedPayload["instructions"]; // cast to JArray
var result = parsedPayload["base"];
Then we can go over instructions and apply them:
foreach (var instruction in instructions) {
// grab target path and value
var targetPath = (string) ((JValue)instruction["patchedPath"]).Value;
var targetValue = (JValue)instruction["patchedValue"];
// temp variable to traverse the path
var target = result;
foreach (var part in targetPath.Split('.')) {
target = target[part];
}
// replace the value
target.Replace(targetValue);
}
Now result contains what was in base with instructions applied.
With Json.NET you can do that like this:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JObject.Parse(json);
var instructions = (JArray)semiParsedJson["instructions"];
var #base = semiParsedJson["base"];
foreach (var instruction in instructions)
{
var path = (string)instruction["patchedPath"];
var newValue = (string)instruction["patchedValue"];
var toBeReplaced = #base.SelectToken(path);
toBeReplaced.Replace(newValue);
}
JObject.Parse parses the json string
With the index operator [] we retrieve the two top level nodes. - One of them is an array (that's why there is an explicit JArray cast)
The other one is a JToken
We iterate through the array and retrieve the path and the newvalue
We use the SelectToken to get the desired node and then apply the replacement via the Replace method.
Please bear in mind that this solution is not bulletproof. You might need to change the indexer operator to TryGetValue to be able to check existence before you perform any operation on the JToken.
You also need to check that the patchedPath is valid at all.

How to remove parent element from json in c#

How to covert the below json
{"data":{"id":12,"name":"jeremy","email":"jeremy#test.com"}}
to
{"id":12,"name":"jeremy","email":"jeremy#test.com"}
I want to remove the "data" element from json.
With json.net it's fairly straightforward
var input = "{\"data\":{\"id\":12,\"name\":\"jeremy\",\"email\":\"jeremy#test.com\"}}";
var result = JObject.Parse(input)["data"].ToString(Formatting.None);
Console.WriteLine(result);
Note : Formatting.None is only to preserve the formatting you had in your original example
Or Text.Json
var result = JsonDocument.Parse(input).RootElement.GetProperty("data").ToString();
Output
{"id":12,"name":"jeremy","email":"jeremy#test.com"}
Additional Resources
JObject.Parse Method (String)
Load a JObject from a string that contains JSON.
JObject.Item Property (String)
Gets or sets the JToken with the specified property name.
JToken.ToString Method (Formatting,JsonConverter[])
Returns the JSON for this token using the given formatting and
converters.
Formatting Enumeration
None 0 No special formatting is applied.
Text.Json
JsonDocument.Parse Method
Provides a mechanism for examining the structural content of a JSON
value without automatically instantiating data values.
JsonDocument.RootElement Property
Gets the root element of this JSON document
JsonElement.GetProperty Method
Gets a JsonElement representing the value of a required property
identified by propertyName.
I have a follow up question on a scenario where I don't want to remove the root element.
{
"keepMe": {
"removeMe": [
{
"id": "1",
"name": "Foo",
"email": "Foo#email.com"
},
{
"id": "2",
"name": "Bar",
"email": "Bar#email.com"
}
]
}
But I wanted it to look like
{
"keepMe": {
{
"id": "1",
"name": "Foo",
"email": "Foo#email.com"
},
{
"id": "2",
"name": "Bar",
"email": "Bar#email.com"
}
}
Using below would not work. Is there another way to do this?
var result = JObject.Parse(input)["keepMe"]["removeMe"].ToString(Formatting.None);
//{
// "id": "1",
// "name": "Foo",
// "email": "Foo#email.com"
//},
//{
// "id": "2",
// "name": "Bar",
// "email": "Bar#email.com"
//}
var result = JObject.Parse(input)["removeMe"].ToString(Formatting.None); //Null Reference
Found the answer using the SelectToken and Replace keyword
var jObj = JObject.Parse(input);
jObj.SelectToken("keepMe").Replace(jObj.SelectToken("keepMe.removeMe"));
string result = jObj.ToString();

'Accessed JObject values with invalid key value: 1. Object property name expected.'

I am trying to get JSON data from an api.
I have this json with me:
{
"elements": [
{
"id": 1,
"name": "Bob",
"address": "abc street",
"hobbies": {
"indoor": "Games, reading books",
"outdoor": ""
}
},
{
"id": 2,
"name": "Mark",
"address": "def street",
"hobbies": {
"indoor": "Games, reading books",
"outdoor": ""
}
}
]
}
I have this code with me:
using(var httpClient = new HttpClient()) {
HttpResponseMessage response = httpClient.GetAsync("api_url_here").Result;
var studentJsonString = response.Content.ReadAsStringAsync().Result;
var Jsresult = new JavaScriptSerializer().Deserialize<dynamic>(studentJsonString).ToString();
JObject jObject = JObject.Parse(Jsresult);
IEnumerable<dynamic> listDyn = jObject[0].Select(items => new StudentModel// gives error here as whole
{
id = items["id"].ToString(),
name = items["name"].ToString(),
address= items["address"].ToString()
});
}
But when I am calling the above method but it is giving me an error:
'Accessed JObject values with invalid key value: 1. Object property name expected.'
What am I missing?
Why are you deserializing twice? The result of
JavaScriptSerializer().Deserialize(customerJsonString)
is already an object. You don't need to parse it again with JObject.Parse(). You can just do
JObject jObject= JObject.Parse(customerJsonString)
Furthermore the result of JObject.Parse() is a dictionary and not an array. It has properties, which you can access by their names. For instance
jObject["elements"]
But of course, the compiler can't possibly predict, that jObject["elements"] will be an IEnumerable, so you will have to make sure of that.
jObject.Value<JArray>("elements").Select(item => ...)
This reads the property elements, of jObject as a JArray.

JObject parse returns extra curly braces

I have a variable projectData that contains a valid json string that is stored in a database.
After doing the following:
JObject obj = new JObject();
obj = JObject.Parse(projectData);
Instead of getting
{
"devices": {
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
}
I get this instead:
{{
"devices": {
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
}}
So basically an aditional { and } were added to my json string.
I have also tried the following:
obj = JsonConvert.DeserializeObject<JObject>(projectData);
and it didnt work.
Why is this a problem to me?
I want to iterate over the obj["devices"] array, and when I do the following
foreach(var d in obj["devices"])
It simply doesnt work because of the double curly braces.
Is there a solution to my problem?
Thank you
{
"devices": {
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
}
Your json shows devices as a json object and not an array. You cannot iterate over it with a for loop.
You can access the data by parsing it first and then accessing the properties by using the [] brackets.
var obj = JObject.Parse(jsonString);
Console.WriteLine(obj["devices"]["device_A"]["id"].Value<string>());
//prints
12345
// To Loop through multiple devices... you can use this.
foreach (var device in ((JObject)obj["devices"]).Properties())
Console.WriteLine(obj["devices"][device.Name]["id"]);
Also, when you are using the debug mode, the watch or locals will show {{ }} because the braces are escaped.
Array version of Json
If your json looked like below, then you can use the for loop to access the elements of the JArray.
{
"devices": [
{
"device_A": {
"id": "12345",
"name": "test",
"enabled": true
}
}
]
}
with the above json, you can use the for loop in the following way,
var obj = JObject.Parse(json);
foreach (var device in obj["devices"])
Console.WriteLine(device["device_A"]["id"]);
// Prints
12345

C# get value from deserialized json object

I'm currently Deserializing a json string using the Newtonsoft.Json nuget packet using the following code:
var data = (JObject)JsonConvert.DeserializeObject(json);
Now I'm receiving an object in the following format:
{{ "meta": { "rap": 2098, "count": 5 }, "data": [ { "name": "Gold Tetramino of Mastery", "rap": 735, "uaid": "16601901", "link": "https://www.roblox.com/Gold-Tetramino-of-Mastery-item?id=5786047", "img": "https://t4.rbxcdn.com/081337d7ea86e6a406512aaa83bbcdeb", "serial": "---", "count": 1 }, { "name": "Silver Tetramino of Accomplishment", "rap": 385, "uaid": "16601900", "link": "https://www.roblox.com/Silver-Tetramino-of-Accomplishment-item?id=5786026", "img": "https://t1.rbxcdn.com/60da69cd76f8dad979326f63f4a5b657", "serial": "---", "count": 1 }, { "name": "Subzero Ski Specs", "rap": 370, "uaid": "155175547", "link": "https://www.roblox.com/Subzero-Ski-Specs-item?id=19644587", "img": "https://t4.rbxcdn.com/8ead2b0418ef418c7650d34103d39b6d", "serial": "---", "count": 1 }, { "name": "Rusty Tetramino of Competence", "rap": 319, "uaid": "16601899", "link": "https://www.roblox.com/Rusty-Tetramino-of-Competence-item?id=5785985", "img": "https://t2.rbxcdn.com/968ad11ee2f4ee0861ae511c419148c8", "serial": "---", "count": 1 }, { "name": "Bluesteel Egg of Genius", "rap": 289, "uaid": "16601902", "link": "https://www.roblox.com/Bluesteel-Egg-of-Genius-item?id=1533893", "img": "https://t7.rbxcdn.com/48bf59fe531dd1ff155e455367e52e73", "serial": "---", "count": 1 } ]}}
Now I'm trying to get the following value from it:
"rap": 2098,
I just need 2098 and I've been trying the following code:
string rap = data["rap"].Value<string>();
But sadly this wouldn't work. Does anyone have a idea how to get the value?
Try:
var result = data["meta"]["rap"].Value<int>();
or
var result = data.SelectToken("meta.rap").ToString();
or if you don't want to want to pass the whole path in, you could just search for the property like this:
var result = data.Descendants()
.OfType<JProperty>()
.FirstOrDefault(x => x.Name == "rap")
?.Value;
Instead of declaring as type var and letting the compiler sort it, declare as a dynamic and using the Parse method.
dynamic data = JArray.Parse(json);
Then try
data.meta.rap
To get the internal rap object.
I edited from using the deserializeobject method as i incorrectly thought that had the dynamic return type. See here on json.net documentation for more details: http://www.newtonsoft.com/json/help/html/QueryJsonDynamic.htm
I just came to add Yet another way to get 2098:
After having got your object in the way you actually did:
var data = (JObject)JsonConvert.DeserializeObject(json);
The first you have to note is that the value you want to get is itself a value of the property "meta":
so, first you have to extract the contents of "meta" by simply calling
data["meta"]
and just then you are able to ask for the Value<string> of "rap":
String rap = data["meta"].Value<string>("rap");
which acctually gives you the value you were looking for:
Console.WriteLine(rap); // 2098
var jobject = (JObject)JsonConvert.DeserializeObject(json);
var jvalue = (JValue)jobject["meta"]["rap"];
Console.WriteLine(jvalue.Value); // 2098
The value is actually an int type. Try:
int rap = data["rap"].Value<int>();
string rap = JsonConvert.DeserializeObject<dynamic>(json).meta.rap;
Console.WriteLine(rap); // 2098
If you're not into dynamic (or aren't using .NET 4+), I like how this other answer relies solely on Json.NET's API.
Try to use as following
var test = JsonConvert.DeserializeObject<dynamic>(param);
var testDTO = new TPRDTO();
testDTO.TPR_ID = test.TPR_ID.Value;
Note: For using of JsonConvert class you have to install Newton-Soft from your package-manager
the problem is that you are casting the deserialized json into a JObject. if you want to have the JObject then simple do this:
JObject.Parse(json);
then you have the JObject and you can access a specific path (for extracting value see this )
you have also another option which is to deserialize your json into a class that you have in your code like this:
var instanceOFTheClass = JsonConvert.DeserializeObject<YourClassName>(json);
with the above code you can access any property and values you want.
Use the enumerator to get at the value:
var data = (JObject)JsonConvert.DeserializeObject(json);
var enumerator = data.GetEnumerator();
enumerator.MoveNext();
var dataValue = enumerator.Current.Value.ToString();
Just use dynamic representation of object:
dynamic obj = JsonConvert.DeserializeObject(json)
var value = obj.meta.rap;
JObject easily convertable to dynamic type itself. You can either get string or int from this value:
var ivalue = (int)obj.meta.rap;
var svalue = (string)obj.meta.rap;

Categories