json add new object to existing json file C# - c#

I'm trying to automate the addition of new objects to an existing JSON file. I looked all around the web but only found adding data and stuff but not a whole object. This is how the file that I want to edit looks:
[
{"id":"123","name":"carl"}
]
and I want to go to
[
{"id":"123","name":"carl"},
{"id":"1234","name":"carl2"}
]
Thank you for all your answers but I don't think everyone completely understands what i mean I have tried some of the answers but then I get this:
[
"{\"id\":\"123\",\"name\":\"carl\"}"
]"{\"id\":\"1234\",\"name\":\"carl2\"}"
and I want everything in between the [].

If you use json.NET you can simply deserialize and serialize the json.
var list = JsonConvert.DeserializeObject<List<Person>>(myJsonString);
list.Add(new Person(1234,"carl2");
var convertedJson = JsonConvert.SerializeObject(list, Formatting.Indented);

Using Json.Net
//load from file
var initialJson = "[{\"id\":\"123\",\"name\":\"carl\"}]";
var array = JArray.Parse(initialJson);
var itemToAdd = new JObject();
itemToAdd["id"] = 1234;
itemToAdd["name"] = "carl2";
array.Add(itemToAdd);
var jsonToOutput = JsonConvert.SerializeObject(array, Formatting.Indented);
//save to file here
Using this method doesn't require strongly typed objects
You could replace this bit:
//load from file
var initialJson = "[{\"id\":\"123\",\"name\":\"carl\"}]";
With
var initialJson = File.ReadAllText(#"c:\myjson.json")
To load the json from a text file

A better performing solution than serializing/deserializing what may be a large file would be to open a FileStream, seek 1 character before the end, then serialize and write your new object into the array, then write a closing bracket. See this question C# How to delete last 2 characters from text file and write into the same line at the end my text?, I'll copy the code here - you already know how to serialize your object and encode it into bytes.
using(var fs = new FileStream("file.json")) {
fs.Seek(-1,SeekOrigin.End);
fs.Write(mySerializedJSONObjAsBytes,0,mySerializedJSONObjAsBytes.Length); // include a leading comma character if required
fs.Write(squareBracketByte, 0, 1);
fs.SetLength(fs.Position); //Only needed if new content may be smaller than old
}
Sorry haven't tested any of that, it's off the top of my head. Pro-tip: wrap FileStream in a StreamWriter so can write strings directly.

You could create a method:
public string AddObjectsToJson<T>(string json, List<T> objects)
{
List<T> list = JsonConvert.DeserializeObject<List<T>>(json);
list.AddRange(objects);
return JsonConvert.SerializeObject(list);
}
Then use it like this:
string baseJson = "[{\"id\":\"123\",\"name\":\"carl\"}]";
List<Person> personsToAdd = new List<Person>() { new Person(1234,"carl2") };
string updatedJson = AddObjectsToJson(baseJson, personsToAdd);

this would be a sample for you:
var list = JsonConvert.DeserializeObject<List<Example>>(json);
Example example = new Example();
example.name = "Product2";
example.id="1";
list.Add(example);
string output = JsonConvert.SerializeObject(list);
public class Example
{
public string id {get;set;}
public string name { get; set; }
}

I have been looking for a solution to this exact question for a week now. I finally figured out how to append it to the existing json array and not add it as a solo object after the array. Make sure you are using WriteAllText and not AppendAllText. Here is what I did:
JArray array = JsonConvert.DeserializeObject<JArray (jsonFile);
JObject obj = new JObject();
obj.Add("ID", "123");
obj.Add("Name", "Brian");
array.Add(obj);
var jsonToOutput = JsonConvert.SerializeObject(array, Formatting.Indented);
File.WriteAllText("fileName.json", jsonToOutput);

Related

How to parse JSON with Newtonsoft?

I created an ASP.NET Application, where I have to parse a csv file with a json structure.
The csv file itself is structured like:
{"Instance":"abc","Date":"2019-06-03T00:00:02.056Z","Identification":"someFunction","Type":"DurationInMs","Value":"5","iserror":"False""}
I get the jsonCsvData as a string and tried to parse it. Then I want to save some of the elements of this json object into a db.
public IActionResult ReadJsonCsvData(string jsonCsvData)
{
Console.WriteLine("ReadJsonCsvData");
ChartData chartData = new ChartData();
var lines = jsonCsvData.Split("\n");
foreach (var line in lines)
{
var values = JObject.Parse(line);
var first = string.Concat(values["Instance"]); //Output for first: ""
}
}
The problem now is, that the variable first is an empty string. The result should be (like in the json structure example above) "abc".
Thank you in advance!
I don't know if it will help but here is my solution (remove one of " at the end of your Json).
I use the "Jobject" to parse Json as I want. Import this two reference.
using Newtonsoft.Json.Linq;
using Newtonsoft;
Then you have to create your JObject :
JObject o = JObject.Parse(myJsonString);
Then to retrieve specifics data, you just have to search in your object just like you do with a dictionary with key :
instanceFromJson = o["Instance"].ToString;
dateFromJson = o["Date"].ToString;
If you have a table in your "instance" json object you can retrieve all data from this list just like that :
foreach (var item in o["Instance"]["tabFromInstanceObject"])
{
MyList.Add(item);
}

Additional text encountered after JSON reading

I have this JSON:
{"id":1,"name":"Alabama"}
{"id":2,"name":"Alaska"}
{"id":3,"name":"Arizona"}
{"id":4,"name":"Arkansas"}
and this code:
string[] testDataFiles = new string[] { StatesOneFileName, StatesTwoFileName, ContinentsFileName };
foreach (var testFile in testDataFiles)
{
using (StreamReader r = new StreamReader(testFile))
{
string json = r.ReadToEnd();
dynamic jsonObjectArray = JsonConvert.DeserializeObject(json);
foreach (var item in jsonObjectArray)
{
expectedPartitions.Add(item.name);
}
}
}
When I run this, however, I get this error:
Additional text encountered after finished reading JSON content: {. Path '', line 2, position 0.
I've read a few StackOverflow suggestions to encase the test data in [], but unfortunately I cannot edit the json file itself. Is there a way to wrap something in my code such that it reads the correct way? Thanks.
Assuming a file that contains a json object per line, as follows:
{"id":1,"name":"Alabama"}
{"id":2,"name":"Alaska"}
{"id":3,"name":"Arizona"}
{"id":4,"name":"Arkansas"}
You can create the following model for your data:
public class State
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name{ get; set; }
}
And then create a simple method that reads the file line by line, as follows:
public static IEnumerable<State> GetStates(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentException("Path to json file cannot be null or whitespace.", nameof(path));
}
if (!File.Exists(path))
{
throw new FileNotFoundException("Could not find json file to parse!", path);
}
foreach (string line in File.ReadLines(path).Where(x => !string.IsNullOrWhiteSpace(x)))
{
State state = JsonConvert.DeserializeObject<State>(line);
yield return state;
}
}
Using the code:
string path = ".....";
// get the list of State objects...
List<State> states = GetStates(path).ToList();
// or just the list of state names
List<string> stateNames = GetStates(path).Select(x => x.Name).ToList();
If this is your json file, it's not correctly formatted... You have multiple json objects in it, but it's neither enclosed in [] to show it's an array of json objects, nor are they delimited by comma.
The best thing you can do here, is to read line at a time, and convert it to json object, since it seems that each line represents one json object.
string json = "start";
using (StreamReader r = new StreamReader(testFile)) {
while (!String.IsNullOrWhiteSpace(json)){
json = r.ReadLine();
dynamic jsonObject = JsonConvert.DeserializeObject(json);
//DO YOUR MAGIC HERE
}
}
Here's one way you could easily fix the syntax errors in the json from that file, without modifying your existing code too much:
foreach (var testFile in testDataFiles)
{
// read the contents of the file with invalid json format, and build a new string named cleanJson with the fixed file contents
string[] fileLines = File.ReadAllLines(testFile);
string cleanJson = "["; // add an opening array bracket to make it valid json syntax
for (int i = 0; i < fileLines.Length; i++)
{
cleanJson += fileLines[i];
if (i < fileLines.Length - 1)
cleanJson += ","; // add a comma to the end of each line (except the last) to make it valid json syntax
}
cleanJson += "]"; // add a closing array bracket to make it valid json syntax
dynamic jsonObjectArray = JsonConvert.DeserializeObject(cleanJson);
foreach (var item in jsonObjectArray)
{
expectedPartitions.Add(item.name);
}
}

Reading two Json Files and merging them in C#

I am trying to read 2 json files using StreamReader, parse them as JObjects and then perform a merge. However I have am receiving the following error when StreamReader is called for the second time:
Error reading JObject from JsonReader. Current JsonReader item is not
an object: StartArray. Path '', line 1, position 1.
For the line:
string jsonUpdateFile = updatesr.ReadToEnd();
The code below:
var path = String.Format("{0}json\\data.json", AppDomain.CurrentDomain.BaseDirectory);
string jsonOldFile = new StreamReader(path).ReadToEnd();
var updatepath = String.Format("{0}json\\update.json", AppDomain.CurrentDomain.BaseDirectory);
string jsonUpdateFile = new StreamReader(updatepath).ReadToEnd();
var jsonO = JObject.Parse(jsonOldFile);
var jsonU = JObject.Parse(jsonUpdateFile);
//merge new json into old json
jsonO.Merge(jsonU);
//save to file
FileInfo file = new FileInfo(path);
file.Directory.Create();
string JsonToSave = JsonConvert.SerializeObject(jsonO);
System.IO.File.WriteAllText(#path, JsonToSave);
What I am trying to do with the merge:
var jsonO = [{"id":"1234","name":"Bruce"},{"id":"5678","name":"Clark"}]
var jsonU = [{"id":"1234","name":"Wayne"}]
var merge = [{"id":"1234","name":"Wayne"},{"id":"5678","name":"Clark"}
You can take JArray and add the second Json to First One i.e, Like this one
var jsonO = JArray.Parse(jsonOldFile);
var jsonU = JArray.Parse(jsonUpdateFile);
foreach(JObject innerData in jsonU )
{
jsonO.Add(innerData);
}
In order to Update the other json I think you can try this one i dont know once give it a shot
var jsonO = JArray.Parse(jsonOldFile);
var jsonU = JArray.Parse(jsonUpdateFile);
var item = jsonO.Children<JObject>();
foreach(JObject innerData in jsonU)
{
if(innerData[Id] == item[Id])
{
item[Name] = innerData[Name];
jsonO.Replace(item["Name"]);
//[or]
jsonO.Add(item["Name"});
}
else
{
jsonO.Add(innerData);
}
}
even i'm a newbie if i'm wrong please do correct me happy to learn it ..
var jsonO = JArray.Parse(jsonOldFile);
var jsonU = JArray.Parse(jsonUpdateFile);
Using JArray rather than JObject allows me to read the files in. Merge doesn't work as expected but that's a question for another thread.
By looking at the error stated in question, my guess is that your update.json file is not in a valid json format. Please use http://jsonlint.com/ to validate your json first.

Unable to parse JSON file format

I have the following JSON in a text file which I am trying to parse.
{
"0":[68],
"1":[154,78,61],
"2":[89,132,146],
"3":[],
"4":[77,132,146],
"5":[32,132,50],
"6":[],
"7":[114,118,54,44,72,136,156,134,129,82,43,34,51,93,142,67,47,153,160,73,39,149,107,94,145,29,115,53,83,1,35,56,123,66,90,121,155],
"8":[89,146],
"9":[89,146],
"10":[100,135],
"11":[],
"12":[],
"13",[111,131],
"14":[77,124],
"15":[89,146],
"16":[163,126,122],
"17":[100,126,135],
"18":[32,50],
"19":[163,126,122]
}
The code I have is
var map = new List<Dictionary<int, List<int>>>();
using (var r = new StreamReader(#"C:\Development\phase2\dependencymap.json"))
{
var json = r.ReadToEnd();
map = JsonConvert.DeserializeObject<List<Dictionary<int, List<int>>>>(json);
}
But it doesn't seem to like the format. What am I doing wrong?
The JSON is malformed. Check the following line
"13" , [111,131],
and change it to:
"13" : [111,131],
Try map = JsonConvert.DeserializeObject<List<Dictionary<String, List<int>>>>(json);
Your keys are String, not int.

Load from XML/JSON as extension method of object rather than string

I have the code below which takes file containing XML and JSON and deserializes the JSON/XML into objects
using (var streamReader = new StreamReader("output.json"))
{
var rawJsonToLoad = streamReader.ReadLine();
var jsonWalkOrder = rawJsonToLoad.FromJson<MeterWalkOrder>();
Debug.WriteLine(jsonWalkOrder.Dump());
}
var xml = File.ReadAllText("WalkOrder.xml");
var xmlTest = xml.LoadFromXML<MeterWalkOrder>();
JSON
{
Name: Red Route,
Meters:
[
{
__type: "WindowsFormsApplication1.Classes.Meter, WindowsFormsApplication1",
MeterID: 1,
SerialNumber: 12345
},
{
__type: "WindowsFormsApplication1.Classes.Meter, WindowsFormsApplication1",
MeterID: 2,
SerialNumber: SE
}
]
}
[
1,
441,
2
]
XML
<MeterWalkOrder>
<Name>Red Route</Name>
<Meters>
<Meter>
<MeterID>1</MeterID>
<SerialNumber>12345</SerialNumber>
</Meter>
<Meter>
<MeterID>2</MeterID>
<SerialNumber>SE</SerialNumber>
</Meter>
</Meters>
</MeterWalkOrder>
Whilst on the surface this does work fine, there is a major drawback with it, it is using extension methods that are all extending the string data type
What I really want to be able to do is to say something like
var xml = File.ReadAllText("WalkOrder.xml");
var xmlTest = new MeterWalkOrder();
xmlTest.LoadFromXML(xml);
How can this be done with an extension method that extends an object rather than string?
I dont like the current approach because there is not enough flexibility in it, it forces the creation of new objects. For example, using the current method if I had a list of 5 meters and I wanted to add another 10 meters from a string of JSON I wouldnt be able to, because the fromJson would force me to recreate my meters list so I would only have the 10 meters in the file, not those 10 + the 5 that were already in the list
Paul
Edit - Following comments I have tried an extension method which actually demonstrates my issue perfectly
public static class ObjectExtensions
{
public static T PopulateFromJson<T>(this T obj)
{
using (var streamReader = new StreamReader("output.json"))
{
var rawJsonToLoad = streamReader.ReadLine();
obj = rawJsonToLoad.FromJson<T>();
}
return obj;
}
}
If I use the code below...
var testJson = new MeterWalkOrder();
testJson.Meters.Add(new Meter() { SerialNumber = "Meter 1" });
testJson.Meters.Add(new Meter() { SerialNumber = "Meter 2" });
testJson.PopulateFromJson();
...
After PopulateFromJson I want the object to be preserved - but because fromJson returns a new object it isnt - so my object would only contain the 2 meters from the JSON file, I actually want them added to the end of the list - in short I want to use the existing object not to have a new one created
Paul

Categories

Resources