Update a json file containing variables from another json file in C# - c#

I have a json config file with values as variables. I want to replace these variables with actual values that are stored in another json file.
Source data json file:
{
"person": {
"id": 15305,
"gender": "Male",
"dob": "1958-10-31T00:00:00",
"name": {
"id": 80587,
"first": "John",
"last": "Dominick"
}
},
"ethnicity": [
{
"id": 2,
"display": "Not Hispanic or Latino",
"kbEthnicity": null
}
],
"race": [
{
"id": 4,
"display": "Black"
},
{
"id": 6,
"display": "Other Race"
}
]
}
Destination data json file:
{
"dryRun": "true",
"person": {
"firstName": "[person.name.first]",
"lastName": "[person.name.last]",
"dateOfBirth": "[person.dob]",
"gender": "[person.gender]",
"race": "[race]"
}
}
Final json file that I want:
{
"dryRun": "true",
"person": {
"firstName": "John",
"lastName": "Dominick",
"dateOfBirth": "1958-10-31T00:00:00",
"gender": "MALE",
"race": "Black, Other Race"
}
}
Here is the code that I wrote using the following SO post that reads both files and is able to extract the correct values from the source file, but I am stuck on what is the best way to create a final json file.
public static void Main(string[] args)
{
var sourceJson = File.ReadAllText("./sourcedata.json");
var srcObj = JObject.Parse(sourceJson);
var destJson = File.ReadAllText("./destinationdata.json");
var destObj = JObject.Parse(destJson);
var result = destObj.Descendants()
.OfType<JProperty>()
.Select(p => new KeyValuePair<string, object>(p.Path,
p.Value.Type == JTokenType.Array || p.Value.Type == JTokenType.Object
? null : p.Value));
foreach (var kvp in result)
{
var isVariable = kvp.Value == null ? false : Regex.IsMatch(kvp.Value.ToString(), #"^\[.*?\]$");
if (isVariable)
{
var variable = Regex.Replace(kvp.Value.ToString(), #"[\[\]]+", "");
Console.WriteLine($"Key: {kvp.Key} Value: {kvp.Value} Updated: {srcObj.SelectToken(variable)}");
}
else
{
Console.WriteLine($"Key: {kvp.Key} Value: {kvp.Value}");
}
}
}
Another issue that I want to solve is how to concatenate the values if there is an array? Any help would be appreciated.

High level: You need two POCO objects: one to deserialize your source json (with the values), and one to serialize to your destination json.
You read in the source, deserialize to the source poco, translate from source poco to destination poco, and then serialize that as destination json.
I think that's much more straightforward than working with JObjects, etc.
Here is a slightly simplified version of your objects:
using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var json = #"{""person"":{""name"": {""first"": ""John"",""last"": ""Dominick""}}}";
var objA = Newtonsoft.Json.JsonConvert.DeserializeObject<Source.MyObject>(json);
Console.WriteLine("FirstName: " + objA.Person.Name.FirstName);
var objB = new Destination.MyObject(objA);
var outJson = Newtonsoft.Json.JsonConvert.SerializeObject(objB);
Console.WriteLine(outJson);
}
}
public class Source{
public class MyObject
{
[JsonProperty("person")]
public Person Person { get; set; }
}
public class Person
{
[JsonProperty("name")]
public Name Name { get; set; }
}
public class Name
{
[JsonProperty("first")]
public string FirstName { get; set; }
[JsonProperty("last")]
public string LastName { get; set; }
}
}
public class Destination{
public class MyObject{
public MyObject(Source.MyObject sourceObject){
Person = new Person();
Person.FirstName = sourceObject.Person.Name.FirstName;
Person.LastName = sourceObject.Person.Name.LastName;
}
[JsonProperty("person")]
public Person Person {get;set;}
}
public class Person
{
[JsonProperty("firstName")]
public string FirstName {get;set;}
[JsonProperty("lastName")]
public string LastName {get;set;}
}
}
Output:
FirstName: John
{"person":{"firstName":"John","lastName":"Dominick"}}
see:
https://dotnetfiddle.net/0V4pEO

Related

Equivalent of JArray.FromObject() in .Net5?

We have a project which using System.Text.Json in .NET 5 instead of Newtonsoft JObject. Using Newtonsoft, it is pretty easy to replace dynamic JSON data e.g. as shown below:
siteDataObject["student"] = JArray.FromObject(studentservice.GetStudents());
When studentservice.GetStudents() is return List as below structure
internal class Student {
public int Id { get; set; }
public string Name { get; set; }
public string ContactPhone { get; set; }
public IEnumerable<MedicalRecord> MedicalRecords { get; set; }
}
internal class MedicalRecord {
public int Id { get; set; }
public string Name { get; set; }
public DateTime RecordDate { get; set; }
public IEnumerable<DiseaseLog> DiseaseLogs{ get; set; }
}
internal class DiseaseLog {
public int Id { get; set; }
public string Name { get; set; }
public DateTime LogDate { get; set; }
}
but in System.Text.Json
foreach (var element in doc.RootElement.EnumerateObject()) {
if (element.Name == "student") {
writer.WritePropertyName(element.Name);
}
else {
element.WriteTo(writer);
}
}
I don't know how to convert List<student> into JSON array data, when student class have many properties with multi collection inside.
Can anyone advise how to convert it ?
To clarify, I need to propose the full code for this, I have a dynamic json string and want to replace element : students into new record, the code will be
var dynamicJson = #"{'roomid':1,'roomcode':'Code001','students':[1],'contentdata':'say hello','footerdata':'cookie policy'}";
using MemoryStream stream = new MemoryStream();
using Utf8JsonWriter writer = new Utf8JsonWriter(stream);
using var dynamicDocument = JsonDocument.Parse(dynamicJson);
writer.WriteStartObject();
foreach (var element in dynamicDocument.RootElement.EnumerateObject())
{
if (element.Name == "students")
{
// unknown how to modify the student record into array
}
else
element.WriteTo(writer);
}
writer.WriteEndObject();
stream.Flush();
var modifyJson = Encoding.UTF8.GetString(stream.ToArray());
I know how to modify student value , if student element is string, but I don't know how to modify it into array, by using simple code. As student have multi class inside.
My expected result should be
{
"roomid": 1,
"roomcode": "Code001",
"students": [
{
"id": 1,
"Name": "Wilson",
"ContactPhone": "123-122-3311",
"MedicalRecords": [
{
"id": 101,
"Name ": "Medial record 101011",
"RecordDate": "2021-12-31",
"DiseaseLogs": [
{
"id": 18211,
"Name ": "Patient Log 19292",
"LogDate": "2020-1-31"
},
{
"id": 18212,
"Name ": "Patient Log 2911w",
"LogDate": "2020-3-31"
}
]
}
]
}
],
"contentdata": "say hello",
"footerdata": "cookie policy"
}
In .NET 5 there is no modifiable JSON Document Object Model built into to System.Text.Json. JsonDocument is read-only, and System.Text.Json.Nodes was only introduced in .NET 6. Thus, the easiest way to deserialize, modify and re-serialize free-form JSON in .NET 5 is to deserialize to some partial data model, with unknown values bound into a dictionary.
If you do not care about the order of properties at the root level, you could deserialize to a model with a public object students { get; set; } property, and bind the remaining elements to a JsonExtensionData overflow dictionary:
public class RootObject
{
public object students { get; set; }
[System.Text.Json.Serialization.JsonExtensionDataAttribute]
public IDictionary<string, object> ExtensionData { get; set; }
}
Then deserialize, modify and re-serialize as follows:
var students = new List<Student> { /* Initialize these as required... */ };
var dynamicJson = #"{""roomid"":1,""roomcode"":""Code001"",""students"":[1],""contentdata"":""say hello"",""footerdata"":""cookie policy""}";
var root = JsonSerializer.Deserialize<RootObject>(dynamicJson);
root.students = students;
var modifyJson = JsonSerializer.Serialize(root, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true });
Which results in
{
"students": [
{
"id": 1,
"name": "Wilson",
"contactPhone": "123-122-3311",
"medicalRecords": [
{
"id": 101,
"name": "Medial record 101011",
"recordDate": "2021-12-31T00:00:00",
"diseaseLogs": [
{
"id": 18211,
"name": "Patient Log 19292",
"logDate": "2020-01-31T00:00:00"
},
{
"id": 18212,
"name": "Patient Log 2911w",
"logDate": "2020-03-31T00:00:00"
}
]
}
]
}
],
"roomid": 1,
"roomcode": "Code001",
"contentdata": "say hello",
"footerdata": "cookie policy"
}
the students property must be declared as object because the input JSON already has an array containing a single integer value; declaring it as public List<Student> students { get; set; } would result in a deserialization when initially loading the JSON.
Demo fiddle #1 here.
If you do care about the order of properties at the root level, you could deserialize to an OrderedDictionary (an old order-preserving non-generic dictionary dating from .NET Framework 2.0 which is still around and supported), overwrite the "students" value, and re-serialize:
var students = new List<Student> { /* Initialize these as required... */ };
var dynamicJson = #"{""roomid"":1,""roomcode"":""Code001"",""students"":[1],""contentdata"":""say hello"",""footerdata"":""cookie policy""}";
var root = JsonSerializer.Deserialize<OrderedDictionary>(dynamicJson);
root["students"] = students;
var modifyJson = JsonSerializer.Serialize(root, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true });
Which results in
{
"roomid": 1,
"roomcode": "Code001",
"students": [
{
"id": 1,
"name": "Wilson",
"contactPhone": "123-122-3311",
"medicalRecords": [
{
"id": 101,
"name": "Medial record 101011",
"recordDate": "2021-12-31T00:00:00",
"diseaseLogs": [
{
"id": 18211,
"name": "Patient Log 19292",
"logDate": "2020-01-31T00:00:00"
},
{
"id": 18212,
"name": "Patient Log 2911w",
"logDate": "2020-03-31T00:00:00"
}
]
}
]
}
],
"contentdata": "say hello",
"footerdata": "cookie policy"
}
Demo fiddle #2 here.
In .NET 6 this all becomes easier through use of the System.Text.Json.Nodes editable JSON Document Object Model:
var dynamicJson = #"{""roomid"":1,""roomcode"":""Code001"",""students"":[1],""contentdata"":""say hello"",""footerdata"":""cookie policy""}";
var nodes = JsonSerializer.Deserialize<JsonObject>(dynamicJson);
nodes["students"] = JsonSerializer.SerializeToNode(students, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
var modifyJson = nodes.ToString();
But in .NET 5 this is not possible. Demo fiddle #3 here.
I think this is what you want (array or single nested object):
var student = new Student()
{
Name = "Student",
ContactPhone = "contact",
Id = 1,
MedicalRecords = new List<MedicalRecord>()
{
new MedicalRecord()
{
Name = "Medical Record 1",
RecordDate= DateTime.Now ,
Id = 1 ,
MedicalRecords = new List<DiseaseLog>()
{
new DiseaseLog(){ Name = "some disease" ,
LogDate = DateTime.Now, Id =1 }
}
}
}
};
var data = System.Text.Json.JsonSerializer.Serialize(student);
Console.WriteLine(data);
var list = new List<Student>();
list.Add(student);
var arrayData = System.Text.Json.JsonSerializer.Serialize(list);
Console.WriteLine(arrayData);

Download values of list from json file

I have simple class
class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public List<string> ParentsNames { get; set; }
}
And a json file
[
{
"Name": "Frank",
"Surname": "Wilson",
"Age": "52",
"Login": "fwillock",
"Password": "willock123",
"ParentsNames": [
"Charles",
"Sarah"
]
},
{
"Name": "Karen",
"Surname": "Davies",
"Age": "35",
"Login": "kdavies",
"Password": "davies123",
"ParentsNames": [
"Jason",
"Angela"
]
}
]
I need to get in console all names or surnames, existing in Person list. I tried to use something like this:
var JsonDeserialize = File.ReadAllText(fileName);
List<Person> result = JsonSerializer.Deserialize<List<Person>>(JsonDeserialize);
Console.WriteLine(result.Select(x => x.Name).ToList());
But i don't have any idea to use it in my code.
Thanks in advance.
list of names
var names= result.Select(i=> new {Name=i.Name, Surname=i.Surname}).ToList();
to print
foreach (var n in result) Console.WriteLine ( $"{n.Name} {n.Surname}");
If you want to customise how you display information in a class one option is to override ToString() for your Person class:
class Person
{
...
// customize however you like
public override string ToString() => $"{Name} {Surname}";
}
Then to display in a single line, you could use string.Join():
Console.WriteLine(string.Join(", ", result));
Or if you want each person on a new line:
result.ForEach(person => Console.WriteLine(person));
// which can be shortened to
result.ForEach(Console.WriteLine);

Compare Property values of two json objects in c#

I have a two json objects like this below,
Json 1:
{
"data": {
"firstName": "xxx",
"lastName": "yyy",
"age": "29"
}
}
Json 2:
{
"data": {
"firstName": "aaa",
"lastName": "yyy",
"age": "30",
"location": "USA"
},
"meta": {
"browser": "chrome",
"ip": "999.999.999"
}
}
How can i compare properties of json 1 with json 2 and return the bool value if values are equal ?
From the above example the firstName value is different in both json objects so the result will return bool value as false , otherwise it will return true.
Please help, thanks in advance !!!
Approach #1 - Using JObject from Newtonsoft.Json Library
var json1 = File.ReadAllText("json1.json");
var json2 = File.ReadAllText("json2.json");
var jObj1 = JObject.Parse(json1);
var jObj2 = JObject.Parse(json2);
if (jObj1["data"]["firstName"] != null && jObj2["data"]["firstName"] != null && jObj1["data"]["firstName"].ToString() == jObj2["data"]["firstName"].ToString())
{
//condition is true
Console.WriteLine("true");
}
else
{
//condition is false
Console.WriteLine("false");
}
Approach #2 - Using Modal & JsonConvert from Newtonsoft.Json Library. I have used json2csharp to convert the json to c# class
public class Data
{
public string firstName { get; set; }
public string lastName { get; set; }
public string age { get; set; }
public string location { get; set; }
}
public class Meta
{
public string browser { get; set; }
public string ip { get; set; }
}
public class Root
{
public Data data { get; set; }
public Meta meta { get; set; }
}
var jObj1 = JsonConvert.DeserializeObject<Root>(json1);
var jObj2 = JsonConvert.DeserializeObject<Root>(json2);
if (jObj1.data.firstName.Equals(jObj2.data.firstName))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}

deserialization of json file to poco object not working

I am trying to instantiate a poco object with data in a .json file in my VS project. When I use this code, it just returns an empty object.
Class:
public class Person
{
public int id { get; set; }
public string name { get; set; }
}
Json text in in file:
{
"person":
{
"id": 1,
"name": "joe"
}
}
Code in Program.cs:
static void Main(string[] args)
{
string jspath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), #"Json\json1.json");
//person object results in 0 for id and null for name (empty)
Person person = new JavaScriptSerializer().Deserialize<Person>(File.ReadAllText(jspath ));
}
What am I doing wrong?
Your JSON file is not correct.
It should be:
{ "id": 1, "name": "joe" }
Proof:
Person p = new Person
{
id = 1,
name = "joe"
};
var sb = new StringBuilder();
new JavaScriptSerializer().Serialize(p, sb);
Console.WriteLine(sb.ToString()); // Outputs: { "id": 1, "name": "joe" }

How to use ShouldSerialize[MemberName]() method for a property of type Object?

I have tried to prevent the property of type object with no new values assigned to its properties using ShouldSerialize Method in Newtonsoft.Json. But I dont know how to implement it, so please help me to solve this...
Here is the sample code
public class Sample1
{
public String name{get;set;}
public int Id{get;set;};
}
And this is my Class containing the above class as one of its properties
public class Container
{
public String Cname{get;set;}
public Sample1 Sample{get;set;};
public bool ShouldSerializeSample()
{
//What should I write here to prevent the Sample property from being serialized when its properties are assigned no new values.
}
}
Given your example classes, I think you you are looking for something like this:
public bool ShouldSerializeSample()
{
return (Sample != null && (Sample.Id != 0 || Sample.name != null));
}
Here is a working demo:
class Program
{
static void Main(string[] args)
{
List<Container> list = new List<Container>
{
new Container
{
Cname = "Will serialize Sample because it has a name",
Sample = new Sample1 { name = "sample 1" }
},
new Container
{
Cname = "Will serialize Sample because it has a non-zero Id",
Sample = new Sample1 { Id = 2 }
},
new Container
{
Cname = "Will serialize Sample because it has a name and an Id",
Sample = new Sample1 { name = "sample 3", Id = 3 }
},
new Container
{
Cname = "Will not serialize Sample because it has default values",
Sample = new Sample1()
},
new Container
{
Cname = "Will not serialize Sample because it is null",
Sample = null
}
};
string json = JsonConvert.SerializeObject(list, Formatting.Indented);
Console.WriteLine(json);
}
}
public class Sample1
{
public String name { get; set; }
public int Id { get; set; }
}
public class Container
{
public String Cname { get; set; }
public Sample1 Sample { get; set; }
public bool ShouldSerializeSample()
{
return (Sample != null && (Sample.Id != 0 || Sample.name != null));
}
}
Here is the output:
[
{
"Cname": "Will serialize Sample because it has a name",
"Sample": {
"name": "sample 1",
"Id": 0
}
},
{
"Cname": "Will serialize Sample because it has a non-zero Id",
"Sample": {
"name": null,
"Id": 2
}
},
{
"Cname": "Will serialize Sample because it has a name and an Id",
"Sample": {
"name": "sample 3",
"Id": 3
}
},
{
"Cname": "Will not serialize Sample because it has default values"
},
{
"Cname": "Will not serialize Sample because it is null"
}
]

Categories