How to update/modify values in Json File - c#

I want to update values in the following type of json file in c#
{"ItemName":"ABC","Id":1}
{"ItemName":"DEF","Id":2}
{"ItemName":"GHI","Id":3}
{"ItemName":"ABC","Id":1}
{"ItemName":"JKL","Id":2}
{"ItemName":"MNO","Id":3}
How can i remove duplicate values based on 'ItemName' and than update Id. Like expected output will be:
{"ItemName":"ABC","Id":1}
{"ItemName":"DEF","Id":2}
{"ItemName":"GHI","Id":3}
{"ItemName":"JKL","Id":4}
{"ItemName":"MNO","Id":5}
I searched alot about json.writer function but couldn't found a solution for a file without using [] and , seperation.
However i can read the file by using below code
var jsonReader = new JsonTextReader(new StringReader(File.ReadAllText("path")))
{
SupportMultipleContent = true
};
var jsonSerializer = new JsonSerializer();
dynamic data = jsonSerializer.Deserialize(jsonReader);
while (jsonReader.Read())
{
String Items_name = data.ItemName;
}

You have a class to deser to:
public record X(string ItemName, int Id);
You read your file deser'ing each line:
var xs = File.ReadAllLines("path").Select(l => JsonConvert.DeserializeObject<X>(l)).ToList();
You remove your duplicates:
var deduped = xs.DistinctBy(x => x.ItemName);
and perform your other manipulations etc (maybe you will want to call ToList on the above). Then you reserialize:
File.WriteAllLines("path", deduped.Select(x => JsonConvert.SerializeObject(x)).ToArray());

Related

C#: Appending Json Object to a Json file already containing data

I have created an object which contains data I want to insert/append to the data currently sitting in a json file.
I have succeeded in getting to to write the data to the file however it overwrites all the data that was there originally.
What i am trying to do is append this Property to the json file whilst keeping all the original information.
This is what I have done so far:
string widthBox = Width.Text.ToString();
string heightBox = Height.Text.ToString();
string WindowSizejson = File.ReadAllText(DownloadConfigFilelocation);
dynamic WindowSizejsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(WindowSizejson);
JObject windowContent = new JObject(
new JProperty("externalSite",
new JObject(
new JProperty("webLogin",
new JObject(
new JProperty("window", "height=" + heightBox + ",width=" + widthBox + ",resizable,scrollbars")
)
)
)
)
);
This is the data currently in the json file that i need to append the above to.
( have blurred out values due to company security reasons)
You have two choices that I can think of:
1.Read the entire file into an object, add your object, and then
rewrite the entire file (poor performance)
var filePath = #"path.json";
// Read existing json data
var jsonData = System.IO.File.ReadAllText(filePath);
// De-serialize to object or create new list
var SomeObjectList= JsonConvert.DeserializeObject<List<T>>(jsonData)
?? new List<T>();
// Add any new
SomeObjectList.Add(new T()
{
Name = "..."
});
SomeObjectList.Add(new T()
{
Name = "..."
});
// edit
var first = SomeObjectList.FirstOrDefault();
first.Name = "...";
// Update json data string
jsonData = JsonConvert.SerializeObject(SomeObjectList);
System.IO.File.WriteAllText(filePath, jsonData);
Open the file read/write,
parse through until you get to the closing curly brace, then write
the remaining data, then write the close curly brace (not trivial)
Instead of messing around with JProperty, deserialize your json and append your desired data:
JObject obj = JObject.Parse(jsontext);
obj["new_prop"] = "value";//new property as per hirarchy ,same for replacing values
string newjson=obj.ToString();
it's much cleaner and easier to maintain.

Newtonsoft Object serialized to String. JObject instance expected

Hi so am trying to parse this JSON line but i got some others that are like this in files thats why i want to automate this so i can remove the invalid lines to make the file a valid JSON for reading, The problem is that the JSON contains multiple JSON in 1 line
Example:
{"item":"value"}{"anotheritem":"value"}
Is there anyway to remove
{"anotheritem":"value"}
So it turns in to a valid JSON that is readable to start parsing the files
I tried doing using StreamReader cause there in a file i have multiple files that contain these invalid JSON
So i got it to be able to detect the Invalid JSON but for some reason i can't get it to read the JSON so i can use .remove to remove the invalid line
using (StreamReader r = new StreamReader(itemDir))
{
string json = r.ReadToEnd();
if (json.Contains("anotheritem"))
{
JObject NoGood = JObject.FromObject(json);
MessageBox.Show(NoGood.ToString());
}
}
The Error:
Object serialized to String. JObject instance expected.
Thank you all for your time and help.
If each object are side by side without space or any other character, you can convert your string to an json array.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
string arrayValue = "[" + value.Replace("}{", "},{") + "]";
var array = JArray.Parse(arrayValue);
var goopArray = array.OfType<JObject>().Where(o => o.Property("anotheritem") == null);
Edit : see my second answer. More robust solution. More modern. And support dotnet core builtin json serializer.
Json.Net
Even better solution, Json.NET have a builtin feature for this exact scenario. See Read Multiple Fragments With JsonReader
The JsonTextReader have a property SupportMultipleContent that allow to read consecutive items when set to true
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var reader = new JsonTextReader(new System.IO.StringReader(value));
reader.SupportMultipleContent = true;
var list = new List<JObject>();
while (reader.Read())
{
var item = JObject.Load(reader);
list.Add(item);
}
System.Text.Json
If you want to use System.Text.Json, it's also acheivable. They are no SupportMultipleContent property but Utf8JsonReader will do the job for you.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var bytes = Encoding.UTF8.GetBytes(value).AsSpan();
var list = new List<JsonDocument>();
while (bytes.Length != 0)
{
var reader = new Utf8JsonReader(bytes);
var item = JsonDocument.ParseValue(ref reader);
list.Add(item);
bytes = bytes.Slice((int) reader.BytesConsumed);
}

How to parse json value that is stored in an array and store selected value in array in c#?

I read json values from a text and store it in array using this code.
string[] allLines = System.IO.File.ReadAllLines("D:\\tweets.txt");
I need to extract certain fields from this array containing Json.
My Json is of this type:
{"Name":"John","Id":"45","Time":"11 pm"}
{"Name":"Pear","Id":"34","Time":"3 pm"}
I want to extract each "Name" in one array and each "Id" in one array, something like this.
string[] Name= null;
string[] Id= null;
for (var i = 0; i < allLines[i].length; i++)
{
Name = allLines[i].Name;
Id = allLines[i].Id;
}
I tried another way using json parsing as well. I can obtain one row at one time json deserialized this way. But then confused how to obtain the selected fields.
StreamReader streamReader = System.IO.File.OpenText("D:\\tweets.txt");
string lineContent = streamReader.ReadLine();
do
{
if (lineContent != null)
{
var a = JsonConvert.DeserializeObject(lineContent);
}
lineContent = streamReader.ReadLine();
}
while (streamReader.Peek() != -1);
streamReader.Close();
Please help.
I recommend using Json.NET to parse JSON, you can download it as a NuGet package.
It has some great documentation about querying JSON here
Querying your JSON with LINQ would look something like:
JObject json = JObject.Parse(json);
var name = from p in json
select (string)p["Name"];
This example uses the NewtonSoft Json library to deserialize your Json into an object. Then, linq is used to pull out the lists that you are interested in.
I have written this example as a Console Application in Visual Studio. You will need to create a new Console Application, then copy this code into it.
Also, to use the NewtonSoft library in your new Console Application, you will need to load it from NuGet. To do this in VisualStudio, you will need to
Right-click on the project name
Click on Manage NuGet Packages...
In the search box on the top right, enter "newtonsoft" (without the quotes)
Newtonsoft.Json should show up in the list. Click it and press the Install button. This will load the binary and set up the references in your project. After that, you can use the sample code shown in this example.
static void Main(string[] args)
{
TestParseJson();
Console.WriteLine();
Console.WriteLine("Press Any Key to End");
Console.ReadLine(); // Wait for input so we can see our output text
}
// 1 - Construct an object used for deserialization. You will need to make this class match the format of the records in your json text file.
public class User
{
public string Name { get; set; }
public int Id { get; set; }
public DateTime Time { get; set; }
}
// 2 - Simulate Json creation and then use the NewtonSoft library to deserialize. You will need to just extract from the DeserializeObject line down
public static void TestParseJson()
{
// Read list of json objects from file, one line at a time. The json in the test file users.json is in this format:
// {"Name":"John","Id":45,"Time":"2015-11-05T19:18:02.0324468Z"}
// {"Name":"Pear","Id":34,"Time":"2015-11-06T19:18:02.0329474Z"}
var jsonLines = File.ReadLines(#"c:\temp\users.json");
var deserializedUsers = jsonLines.Select(JsonConvert.DeserializeObject<User>).ToList();
// Use Linq to project the list of deserializedUsers into the lists that you want
var names = deserializedUsers.Select(user => user.Name);
var ids = deserializedUsers.Select(user => user.Id);
// Output list of names and ids for debugging purposes
Console.WriteLine("");
Console.WriteLine(" Names:");
foreach (var name in names)
{
Console.WriteLine(" " + name);
}
Console.WriteLine(" Ids:");
foreach (var id in ids)
{
Console.WriteLine(" " + id);
}
}
Your JSON does not actually represent an array, but rather a series of individual objects back-to-back. To be considered a valid JSON array, the objects would need to be enclosed in square brackets and separated by commas (see JSON.org). Regardless, it is still possible to read and parse this non-standard JSON using Json.Net. The JsonTextReader class has a special SupportMultipleContent setting that is designed to cope with this situation. You can process your file using the following code:
List<string> names = new List<string>();
List<string> ids = new List<string>();
JsonSerializer serializer = new JsonSerializer();
using (StreamReader sr = new StreamReader("D:\\tweets.txt"))
using (JsonTextReader reader = new JsonTextReader(sr))
{
reader.SupportMultipleContent = true;
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
JObject jo = JObject.Load(reader);
names.Add((string)jo["Name"]);
ids.Add((string)jo["Id"]);
}
}
}
Console.WriteLine("Names: " + string.Join(", ", names));
Console.WriteLine("Ids: " + string.Join(", ", ids));
Fiddle: https://dotnetfiddle.net/tYVLLr

Find differences between two json objects

Are there any libraries in .Net to help compare and find differences between two json objects? I've found some solutions available for JavaScript, but nothing interesting for C#. The point of my question is to create json with changes marked in some way, based on the comparison. So that the user could see where the changes are.
using Microsoft.XmlDiffPatch;
using Newtonsoft.Json;
Convert each json to xml and use MS XmlDiff libary. Available on nuget. Differences are given in another xml doc which here I write to the console. This is suitable for unit testing for example.
public bool CompareJson(string expected, string actual)
{
var expectedDoc = JsonConvert.DeserializeXmlNode(expected, "root");
var actualDoc = JsonConvert.DeserializeXmlNode(actual, "root");
var diff = new XmlDiff(XmlDiffOptions.IgnoreWhitespace |
XmlDiffOptions.IgnoreChildOrder);
using (var ms = new MemoryStream())
using (var writer = new XmlTextWriter(ms, Encoding.UTF8))
{
var result = diff.Compare(expectedDoc, actualDoc, writer);
if (!result)
{
ms.Seek(0, SeekOrigin.Begin);
Console.WriteLine(new StreamReader(ms).ReadToEnd());
}
return result;
}
}
I have used different JSON objects than those in your example but it will apply to your case correctly.
private static string GetJsonDiff(string action, string existing, string modified, string objectType)
{
// convert JSON to object
JObject xptJson = JObject.Parse(modified);
JObject actualJson = JObject.Parse(existing);
// read properties
var xptProps = xptJson.Properties().ToList();
var actProps = actualJson.Properties().ToList();
// find differing properties
var auditLog = (from existingProp in actProps
from modifiedProp in xptProps
where modifiedProp.Path.Equals(existingProp.Path)
where !modifiedProp.Value.ToString().Equals(existingProp.Value.ToString())
select new AuditLog
{
Field = existingProp.Path,
OldValue = existingProp.Value.ToString(),
NewValue = modifiedProp.Value.ToString(),
Action = action, ActionBy = GetUserName(),
ActionDate = DateTime.UtcNow.ToLongDateString(),
ObjectType = objectType
}).ToList();
return JsonConvert.SerializeObject(auditLog);
}
I think your best bet is to use JSON.NET to create two JSON objects, then recursively loop through the tree, comparing each node to see if it exists and is equal while you go.
I think the best way to go here is to create objects using newtonsoft json.http://www.nuget.org/packages/newtonsoft.json/
So, you will have two objects of the same type, which you can easily compare and mark the differences.
private IEnumerable<JProperty> JSONCompare(string expectedJSON, string actualJSON)
{
// convert JSON to object
JObject xptJson = JObject.Parse(expectedJSON);
JObject actualJson = JObject.Parse(actualJSON);
// read properties
var xptProps = xptJson.Properties().ToList();
var actProps = actualJson.Properties().ToList();
// find missing properties
var missingProps = xptProps.Where(expected => actProps.Where(actual => actual.Name == expected.Name).Count() == 0);
return missingProps;
}

Parsing large json

I'm trying to parse a json file and then operate on it to insert data into a SQL Server 2008 Database.
Example:
var sr = new StreamReader("C:\\path to file\file.json");
var json = JsonSerializer.SerializeToString(sr);
var o = JsonObject.Parse(json);
But I always get this error at the second line - "Timeouts are not supported on this stream."
The Json file looks like this:
"main":{
"prg": [
{
"Id": 1,
"name": "A&E",
more fields
}
"prg": [
{
"Id": 2,
"name": "asda",
more fields
}
}
I need to make something like this
foreach (prg in main)
entity.id = prg.id
entity.name = prg.name
How can I do this and why I get that timeout exception?
EDIT: To better understand my question this is how I do for an XML file
XmlDocument sourceDoc = new XmlDocument();
sourceDoc.Load(SourcesElement2); // where SourcesElement2 is the path to my XML
XmlNodeList prg = sourceDoc.GetElementsByTagName("prg");
foreach (XmlNode item in prg)
{
entity.Name= item.SelectSingleNode("name").InnerText;
...
}
I have converted the XML to Json and I want to do same thing. For every "prg" node in the Json File insert a new item in the database
EDIT2:
This is what I've done.
using (
StreamReader stream =
File.OpenText(
"C:\\path\\Sources.json")
)
{
JObject sources = (JObject) JToken.ReadFrom(new JsonTextReader(stream));
var a = sources["on"];
var b = a["sources"];
var c = b["prgs"];
foreach (var item in c)
{
var d= item.SelectToken("prg");
// Here d is null
}
I have the same question as the one from above. For every "prg" node in the Json File insert a new item in the database. How can I do this ? ( path to prg is on/sources/prgs/ )
I don't think you want to serialize the stream.
JsonSerializer.SerializeToString(sr)
You want to deserialize from the stream.
JsonSerializer.Deserialize
You might want to use JsonReader for performance reasons.
Your XML example load the whole file in the memory - you don't want to do that for large documents. reader.Read() pattern is better suited for processing large files.
For everyone with the same problem here is what I've done ( NOTE: this is just an example )
By the way, thank you for everyone who tried to answer my question and I'm sorry for my mistakes.
List<string> d = new List<string>();
using (
StreamReader stream =
File.OpenText(
"C:\\path\\Sources.json")
)
{
JObject sources = (JObject) JToken.ReadFrom(new JsonTextReader(stream));
var a = sources["on"];
var b = a["sources"];
var c = b["prgs"];
foreach (JObject item in c["prg"].ToList())
{
d.Add(item.Value<string>("name"));
}
}
//part below is just for testing
foreach (var VARIABLE in d)
{
Console.WriteLine(VARIABLE);
}
Console.ReadLine();
I would approach it by converting that JSON object into a C# class and then applying logic to the C# object and/or use DataTables
[Note: There are solutions online that show you would to easily pass an Object or List<Object> into a DataTable and then pass it "easily" to SQL]
The first step is still your hiccup in either solution, how do I pull in a large JSON string from filesystem?
if you have the JSON, use json2csharp.com and/or jsonutils.com to retrieve the classes in order to Deserialize it to your object.
StreamReader re = new StreamReader(#"C:\path to file\file.json");
JsonTextReader reader = new JsonTextReader(re);
YourClass DeserializedObject = se.Deserialize<YourClass>(reader);
Console.WriteLine(DeserializeObject.SomeProperty);

Categories