Serialize/Deserialize nested objects in flat structure - c#

I'm sure that somewhere there is a simple answer to my question, but I couldn't fin it. The problem I faced is following, I have code structure:
class Field
{
List<Block> Blocks {get;set;}
public static Field CreateField()
{
var A = new Block {Connector = new Connector()}
var B = new Block {Connector = new Connector()}
A.Connector.ConnectedTo.Add(B);
B.Connector.ConnectedTo.Add(A);
var field = new Field();
field.Blocks = new List {A, B};
return field;
}
}
class Block
{
Connector Connector {get;set;}
}
class Connector
{
List<Block> ConnectedTo {get;set;}
}
Than serialization command using json.net:
JsonConvert.SerializeObject(Field.CreateField(), Formatting.Indented, new JsonSerializerSettings {PreserveReferencesHandling = PreserveReferencesHandling.Objects});
and output result is as expected:
{
"$id": "1",
"Blocks": [
{
"$id": "2",
"Connector": {
"$id": "3",
"ConnectedTo": [
{
"$id": "4",
"Connector":{
"$id": "5",
"ConnectedTo": [
{
"$ref": "2"
}
]
}
}
]
}
}
]
}
Is there any way to have serialization result as following:
{
"$id": "1",
"Blocks": [
{
"$id": "2",
"Connector": {
"$id": "3",
"ConnectedTo": [
{
"$ref": "4"
}
]
}
},
{
"$id": "4",
"Connector":{
"$id": "5",
"ConnectedTo": [
{
"$ref": "2"
}
]
}
}
]
}
Thanks.

No. In your second example, $ref : 4 points to an $id that occurs later in the JSON. Json.Net will not be able to deserialize this-- when it comes upon a $ref it expects to be able to resolve it to an $id that it has already seen.
I would recommend against requiring users modify JSON directly anyway unless they are technically savvy. As I've seen from answering many JSON-related questions on SO, it is very easy to get the format messed up if you edit it manually-- missing quotes or commas, mismatched braces, invalid syntax, you name it. What will you do when someone screws it up? I think a better option is to make a tool that allows manipulating your structure abstractly. The tool could deserialize the original JSON, allow certain changes and then reserialize it into the new structure. Users would not need to know anything about the underlying JSON format that way.

Related

Unable to iterate Jobject when having single value

I am using for each to iterate and get values of a json object in my solution.
Let me give example of the json.
[
{
"#Seq": "1",
"#text": "123456789"
},
{
"#Seq": "2",
"#text": "abc"
},
{
"#Seq": "3",
"#text": "xyz"
}
]
It works well for multiple sequences until we have only one seq in the json.
example:
{{
"#Seq": "1",
"#text": "123456789"
}}
Coming to Code:
foreach (var installinst in atpmessage["AUTOPILOTMessage"]["AUTOPILOTBody"]["OrderHeader"]["InstallationInstructions"]["InstallationInstruction"])
{
responseISGEMEA.data.install_instruct =installinst["#text"].ToString();
}
The installinst in the loop gives me just the Seq. Not the text.
{"#Seq": "1"}
how do I make it work with single and multiple sequences.

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

C# How to combine multiple JSON arrays that are part of a List?

What has been done so far?
I am working on dividing up the number of records into 3 batches and processing them in parallel to increase the performance. However, after processing the batches in parallel I would also like to save the outcome (JSON string) of the processed records in a variable.
As you can see below, I first initialize the variable as List of string and then run the foreach loop which saves the processed outcome as mentioned below.
List<string> responseOutcome = new List<string>();
Parallel.ForEach(recordBatches, batch => {
responseOutcome.Add(response1.Content);
});
Result in List responseOutcome comes as:
responseOutcome[0]
[
{
"Name": "Sample1",
"ID": "123"
},
{
"Name": "Sample2",
"ID": "394"
}
],
responseOutcome[1]
[
{
"Name": "Sample5",
"ID": "384"
},
{
"Name": "Sample6",
"ID": "495"
}
],
responseOutcome[2]
[
{
"Name": "Sample3",
"ID": "473"
},
{
"Name": "Sample4",
"ID": "264"
}
]
What I would like to achieve?
Now I would like to take the value of responseOutcome which is multiple arrays of JSON string and merge them into one big JSON string.
Final Output
[
{
"Name": "Sample1",
"ID": "123"
},
{
"Name": "Sample2",
"ID": "394"
},
{
"Name": "Sample5",
"ID": "384"
},
{
"Name": "Sample6",
"ID": "495"
},
{
"Name": "Sample3",
"ID": "473"
},
{
"Name": "Sample4",
"ID": "264"
}
]
I looked into several similar cases but they weren't nearly similar. Like:
How do I merge multiple json objects
How do I combine two arrays from two JObjects in Newtonsoft JSON.Net?
Any help/guidance will be great!!
Using Newtonsoft, you can create a JArray from each of your responses. Then you can flatten the hierarchy using linq's SelectMany method and re-serialize the object.
Try this:
var obj = responses.Select(r => JArray.Parse(r.Trim(','))).SelectMany(token => token);
string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
There are probably more efficient ways to do this if you want to do pure string manipulation, but using Newtonsoft, I would deserialize, merge and then re-serialize.
Create a small POCO model:
public class ResponseOutcomeModel
{
public string ID { get; set; }
public string Name { get; set; }
}
Then deserialize to this model, merge and reserialize to JSON as a single list.
var outcomeList = new List<ResponseOutcomeModel>();
foreach (var i in responseOutcome)
{
outcomeList.AddRange(JsonConvert.DeserializeObject<List<ResponseOutcomeModel>>(i.Trim().TrimEnd(',')));
}
var finalJson = JsonConvert.SerializeObject(outcomeList);
Note, the Time/TrimEnd is used if the trailing commas in your example are really there in your responseOutcome array (at the end of each element in the array). The call to DeserializeObject will complain if you leave the commas in there.

Convert JSON [][] to object in c#

I have a little problem converting my JSON Object I have to something I can work within C# code.
{ "CheckboxHours": {
"method": "ID",
"valueparts": [
"Hour",
[ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23" ]
]
}
}
This is my JSON String I have, which is for creates me the Selenium Object.
What i want is to combine the values from valueparts[0] ("Hour") with valueparts[1][0-23] with each other and create an array of Selenium Objects
var jsonData = JsonConvert.DeserializeObject<jsonc#file>(_jsonFile);
Object[] hours = (Object[])jsonData.CheckboxHours.Valueparts[1];
SeleniumCheckBox[] checkbox = new SeleniumCheckBox[hours.Length];
for (int i = 0; i < hours.Length; ++i)
{
cbHour[i] = new SeleniumCheckBox(jsonData.CheckboxHours.Valueparts[0].ToString() + hours[i]);
}
The SeleniumCheckBox is a Class I made which just takes the value and creates in the background a new Selenium Element with findElement(By.ID(value)). This is working already.
My Problem here is that he doesn't allow the Conversion from jsonData to Object[] and I don't really know how I can handle this.
I hope it is clear what I want to have - if not feel free to ask for more specific data.
I think. You can try this.
var jsonData = JsonConvert.DeserializeObject<dynamic>(_jsonFile);
var hours = jsonData.CheckboxHours.valueparts[1];
foreach (var hour in hours)
{
//Some code
}
I am not sure if I understood everything correctly, but the reason for failure in deserialization might be that valueparts is List parameter, usually in c# the Lists contain only 1 type of parameters eg. string, or int. In your case, "Hour" (valueparts[0]) is a string, and valueparts[1] is List. I assume here is the conflict with deserializing the JSON string.
{
CheckboxHours:{
"method":"ID",
"valueparts":{
Measure: "Hour",
MesureValues:
[
"0","1","2","3","4","5","6","7",
"8","9","10","11","12","13","14",
"15","16","17","18","19","20",
"21","22","23"
]
}
}
}
Change valueparts to object, as in the code above, so you can use Hour as string and the values as List.

Add data array into existing property

I've tried different solutions but I'm not reaching anywhere.
I'm in a middle of a loop and sometimes I need to add data to an existing property (details in this case).
So, in the beginning I create the following JObject without any problem:
var json = JsonConvert.SerializeObject(
new {
details = new[]{
new{product_name = detail["product_name"].ToString(),
quantity = detail["quantity"].ToString(),
product_options = detail["product_options"].ToString()},
}
}
);
// _elements is an dictionary<int, JObject>
_elements.Add(id, JObject.Parse(json));
// output
{
"details": [
{
"product_name": "Oranges",
"quantity": "2",
"product_options": [],
}
]
}
But, for some reason, I need to add more products to the list of details, so I would like my output to be:
{
"details": [
{
"product_name": "Oranges",
"quantity": "2",
"product_options": [],
},
{
"product_name": "Coca Cola",
"quantity": "5",
"product_options": [],
}
]
}
I've tried so far without any success:
dic.Value.Property("details").Add(json);
dic.Value.SelectToken("details").Add(json);
Solved.
dic.Value["details"].Last.AddAfterSelf(JObject.Parse(json));

Categories