I have problem with serialization and deserialization in JSON
I've made 2 tasks to read from JSON file which looks like this:
[
{
"ID": 1,
"OIB": 123456789,
"ime": "name",
"prezime": "surname",
"grad": "city"
}
]
Now I have to add another client with ID 2, with new user informations.
I can read this JSON file with no problems, but I am stuck on writing into the same file.
public struct Klijent
{
public int ID { get; set; }
public long OIB { get; set; }
public string ime { get; set; }
public string prezime { get; set; }
public string grad { get; set; }
}
"FetchClient" from JSON
public static List<Klijent> DohvatiKlijente()
{
List<Klijent> lKlijent = new List<Klijent>();
StreamReader klijent = new StreamReader("x");
string sJson = "";
using (klijent)
{
sJson = klijent.ReadToEnd();
lKlijent = JsonConvert.DeserializeObject<List<Klijent>>(sJson);
}
return lKlijent;
}
"AddClient" to JSON
OIB -> personal identificator
ID -> should go +1 with every entry of client
grad -> city
ime -> name
prezime -> surname
public static void DodavanjeKlijenata()
{
Console.Write("Unesite OIB klijenta: ");
string pOIB = Console.ReadLine();
long nullOIB = 0;
long.TryParse(pOIB, out nullOIB);
int id = 0;
Console.Write("Unesite ime klijenta: ");
string ime1 = Console.ReadLine();
Console.Write("Unesite prezime klijenta: ");
string prezime1 = Console.ReadLine();
Console.Write("Unesite grad klijenta: ");
string grad1 = Console.ReadLine();
List<Klijent> lKlijent = DohvatiKlijente();
foreach (var Klijent in lKlijent)
{
id = Klijent.ID + 1;
}
Klijent dKlijent = new Klijent()
{
ID = id,
OIB = nullOIB,
ime = ime1,
prezime = prezime1,
grad = grad1
};
var serializer = new JsonSerializer();
using (var sw = new StreamWriter("x"))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, dKlijent);
}
}
This code does work, but it seems to delete every time my JSON file and it's format is in one line only, I would like to have it in multiple lines.
Thank you :)
There are two things that you need to do here
Ensure new Client is appended to existing list
For this you can add the new client to the List
lKlijent.Add(dKlijent);
Now you need to serialize the List, instead of lKlijent
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, lKlijent);
}
Formatting
For formatting you can use Formatting Settings. For example,
var serializer = new JsonSerializer() { Formatting = Formatting.Indented} ;
Additional Comments
1. Calculation of ID
Instead of calculating the new ID using the following loop,
foreach (var Klijent in lKlijent)
{
id = Klijent.ID + 1;
}
You could use Enumerable.Last() to get the last client in the list. For example,
var id = lKlijent?.Any()!=true? 0:lKlijent.Last().ID;
2. Rewriting DohvatiKlijente method
The DohvatiKlijente method could rewritten as
public static List<Klijent> DohvatiKlijente()
{
return JsonConvert.DeserializeObject<List<Klijent>>(File.ReadAllText("C:\\Users\\Hrvoje\\Desktop\\Polica Osiguranja MAIN\\Polica Osiguranja\\klijent.json"));
}
Similarly, writing back to file can be simplified as
var jsonString = JsonConvert.SerializeObject(lKlijent,Newtonsoft.Json.Formatting.Indented);
File.WriteAllText(outputFilePath,jsonString);
Related
I've written some code which has to read through 5,000 JSON files and replace a number which appears twice in each file. It's set to create a new json file and delete the old one, with that, other data must be transferred into the new file too, which is not a problem, however we have a list called attributes that contain some text that use single quotes (for punctuation.) - however when the new json file is written, the text with the single quotes is changed and the single quote is replaced with \u0027
Example: old file contains:"0.png" and "Hen's Secret Bra" which in the new file is changing to "5000.png" correct, and "Hen\u0027s Secret Bra" incorrect. How do I transfer the single quote over properly?
Here is my code:
using System.Text.Json;
using System.Web;
internal class Program
{
private static void Main(string[] args)
{
//get all the json files
var jsonPath = #"/Users/jasonnienaber/Desktop/nft/cef/official/fatJSONselfFIX/test";
var jsonFiles = Directory.GetFiles(jsonPath, "*.json");
//loop through each file and process according to specs
foreach(var jsonFile in jsonFiles)
{
var json = File.ReadAllText(jsonFile);
var sample = JsonSerializer.Deserialize<Sample>(json);
var sampleNew = new SampleNew();
var intCounter = 0;
var newIntCounter = intCounter+5000;
var Counter = intCounter.ToString();
var newCounter = newIntCounter.ToString();
sampleNew.image = sample.image.Replace(Counter, newCounter);
sampleNew.name = sample.name.Replace(Counter, newCounter);
sampleNew.description = sample.description;
sampleNew.external_url = sample.external_url;
sampleNew.attributes = sample.attributes;
// serialize JSON to a string and then write string to a file
File.Delete(jsonFile);
File.WriteAllText(jsonFile, JsonSerializer.Serialize(sampleNew));
intCounter++;
}
}
public class Attribute
{
public string trait_type { get; set; }
public string value { get; set; }
}
public class Sample
{
// public string dna { get; set; }
public string image { get; set; }
public string name { get; set; }
public string description { get; set; }
public string external_url { get; set; }
public List<Attribute> attributes { get; set; }
public string compiler { get; set; }
}
public class SampleNew
{
public string image { get; set; }
public string name { get; set; }
public string description { get; set; }
public string external_url { get; set; }
//public List<Attribute> attributes { get; set; }
public List<Attribute> attributes {get; set;}
}
}
The "Hen's Secret Bra" is within attributes
Like Jon Skeet mentioned, it's valid to use \u0027, however, you can change the serializer encoding options:
using System.Text.Json;
var obj = new
{
Name = "John's awesome object",
Age = 31
};
var options = new JsonSerializerOptions
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
// writes obj to json file
File.WriteAllText("obj.json", JsonSerializer.Serialize(obj, options));
Outputs
{"Name":"John's awesome object","Age":31}
So in your code, you can do as follows:
var options = new JsonSerializerOptions
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
//loop through each file and process according to specs
foreach (var jsonFile in jsonFiles)
{
var json = File.ReadAllText(jsonFile);
var sample = JsonSerializer.Deserialize<Sample>(json);
var sampleNew = new SampleNew();
var intCounter = 0;
var newIntCounter = intCounter + 5000;
var Counter = intCounter.ToString();
var newCounter = newIntCounter.ToString();
sampleNew.image = sample.image.Replace(Counter, newCounter);
sampleNew.name = sample.name.Replace(Counter, newCounter);
sampleNew.description = sample.description;
sampleNew.external_url = sample.external_url;
sampleNew.attributes = sample.attributes;
// serialize JSON to a string and then write string to a file
File.Delete(jsonFile);
// use serializer options
File.WriteAllText(jsonFile, JsonSerializer.Serialize(sampleNew, options));
intCounter++;
}
See UnsafeRelaxedJsonEscaping
It is better to use Newtonsoft.Json to avoid any problems like this one.
But one of the thing you can try to fix an issue is to use a serialize options
var options = new JsonSerializerOptions
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
but it is unsafe
Another option is more awkward but more safe, since it affects only one symbol, not any as in the first case
var attr= new Attribute{trait_type="trait_type", value="Hen's Secret Bra"};
attr.value=attr.value.Replace("'","==="); //or you can try something else if you don't like ===
var json=System.Text.Json.JsonSerializer.Serialize(attr);
json=json.Replace("===","'");
File.WriteAllText(jsonFile, json);
json = File.ReadAllText(jsonFile);
result
{"trait_type":"trait_type","value":"Hen's Secret Bra"}
{
"12": {
"_agicId": 2,
"_index_": "",
"_seq": 1
},
"11": {
"_agicId": 1,
"_index_": "",
"_seq": 2
},
"10": {
"_agicId": 0,
"_index_": "",
"_seq": 3
}
}
I get a json string like above, but i don't know "12""11""10", how can i parser this json get _seq & agicId?
var Name = JObject.Parse(r);
int Count = Name.Count;
for (int i = 0; i < Name.Count; i++)
{
// how can i get "11"{"agicId":0}
}
For this create a model class like below:
class Test
{
public int _agicId { get; set; }
public string _index_ { get; set; }
public string _seq { get; set; }
}
And then read the json like below. I have read from file . you can read from string also. In the key you will get 11, 12 etc...and in value you will get the Text class having values for "agicId" etc...
using (StreamReader r = new StreamReader("data.json"))
{
string jsonString = r.ReadToEnd();
JObject jsonObj = JObject.Parse(jsonString);
var k = JsonConvert.DeserializeObject<Dictionary<string, Test>>(jsonString);
/*
A very good suggestion by Jon Skeet. No need of this foreach loop. Instead of criticising he has suggested a better solution.
foreach(var item in jsonObj)
{
string key = item.Key;
var value = JsonConvert.DeserializeObject<Test>(item.Value.ToString());
}*/
}
I keep getting "Additional text encountered after finished reading JSON content" when deserializing. I've tried placing the whole "output" into square brackets, didn't work out.
Full error message
Newtonsoft.Json.JsonReaderException:
'Error reading JObject from JsonReader. Current JsonReader item is not an object:
StartArray. Path '', line 1, position 1.'
These are my 2 objects. NOTE: Values are currently commented for easier "output" reading.
class ItemSerObj
{
public string ItemName { get; set; }
/*
public string Value { get; set; }
public string Quality { get; set; }
public string TimeStamp { get; set; }*/
}
.
class GroupSerObj
{
public string GroupName { get; set; }
/*
public string UpdateRate { get; set; }
public string Active { get; set; }*/
public List<ItemSerObj> Items { get; set; }
}
How I serilzed them.
JsonSerializer serializer = new JsonSerializer();
using (StreamWriter sw = new StreamWriter(path + "\\data.txt"))
{
using (JsonWriter writer = new JsonTextWriter(sw))
{
foreach (ListViewItem group in lV_groups.Items)
{
List<ItemSerObj> itemsObj = new List<ItemSerObj>();
tempOPCServer.opcGroup = tempOPCServer.opcServer.OPCGroups.GetOPCGroup(group.SubItems[0].Text);
foreach (OPCItem item in tempOPCServer.opcGroup.OPCItems)
{
ListViewItem listViewItem = new ListViewItem();
listViewItem.Name = item.ItemID.Substring(item.ItemID.LastIndexOf('.') + 1);
itemsObj.Add(
new ItemSerObj
{
ItemName = listViewItem.Name
/*ItemName = item.SubItems[0].Text/*,
Value = item.SubItems[1].Text,
Quality = item.SubItems[2].Text,
TimeStamp = item.SubItems[3].Text*/
});
}
GroupSerObj serializeGroup = new GroupSerObj
{
GroupName = group.SubItems[0].Text,/*
UpdateRate = group.SubItems[1].Text,
Active = group.SubItems[2].Text,*/
Items = itemsObj
};
serializer.Serialize(writer, serializeGroup);
}
}
}
The output.
{"GroupName":"Group0","Items":[{"ItemName":"Int1"},{"ItemName":"Money"},{"ItemName":"Int4"},{"ItemName":"Int2"}]}{"GroupName":"Group1","Items":[]}{"GroupName":"Group2","Items":[]}
More readable sorting
{"GroupName":"Group0","Items":[
{"ItemName":"Int1"},
{"ItemName":"Money"},
{"ItemName":"Int4"},
{"ItemName":"Int2"}]}
{"GroupName":"Group1","Items":[
]}
{"GroupName":"Group2","Items":[
]}
What I've tried to deserialize it.
string fromJson;
using (StreamReader sr = new StreamReader(path + "\\data.txt"))
{
fromJson = #sr.ReadLine();
}
JObject fromJsonObject = JObject.Parse(fromJson); //Where exeption occurs.
IList<JToken> results = fromJsonObject["Items"]["ItemName"].Children().ToList();
IList<GroupSerObj> deserResults = new List<GroupSerObj>();
foreach(JToken result in results)
{
GroupSerObj deserResult = result.ToObject<GroupSerObj>();
deserResults.Add(deserResult);
}
For me it looks like your output is wrong. Its an array of objects (multiple groups) so it should be surrounded by [ and ] and each object separated by a comma (,).
Your output should look like this:
[{"GroupName":"Group0","Items":[{"ItemName":"Int1"},{"ItemName":"Money"},{"ItemName":"Int4"},{"ItemName":"Int2"}]},{"GroupName":"Group1","Items":[]},{"GroupName":"Group2","Items":[]}]
You are using a JObject to Parse the Array, but when paring an array we need the JArray, so it should be:
JArray fromJsonObject = JArray.Parse(fromJson); //Where exeption occurs.
for (int i = 0; i < fromJsonObject.Count; i++)
{
IList<GroupSerObj> deserResults = new List<GroupSerObj>();
var deserResult = fromJsonObject[i].ToObject<GroupSerObj>();
deserResults.Add(deserResult);
}
I want to load the highscore of an XML file and spend the first place in a label. How do I manage to read the first entry and spend its value?
public class Highscore_obj
{
public string Name { get; set; }
public int Score { get; set; }
}
class Highscore
{
public Highscore_obj[] Score_array = new Highscore_obj[4];
public void LoadXmL(string path)
{
XmlDocument XML = new XmlDocument();
using (Stream s = File.OpenRead(path))
{
XML.Load(s);
}
Score_array[0].Name = "Alex";
Score_array[0].Score = 1000;
Score_array[1].Name = "Chris";
Score_array[1].Score = 940;
Score_array[2].Name = "Stefan";
Score_array[2].Score = 700;
XmlNodeList Highscores = XML.ChildNodes;
}
When I start my game the Highscore of Alex must be visible in the label.
Instead of an Array I would rather suggest using a List. Then you can use Linq to query your list and sort by score descending. I would also rather use serialization and deserialization to load and store your List to and from XML.
The code below illustrates this and should get you on the right track.
internal List<Highscore> Highscores { get; set; }
public void LoadXmL(string path)
{
List<Highscore> highscores = null;
XmlSerializer ser = new XmlSerializer(typeof(List<Highscore>));
using (XmlReader reader = XmlReader.Create(path))
{
highscores = (List<Highscore>)ser.Deserialize(reader);
}
if (highscores == null)
{
highscores = new List<Highscore>
{
new Highscore{ Name = "Alex", Score = 1000 },
new Highscore{ Name = "Chris", Score = 940 },
new Highscore{ Name = "Stefan", Score = 700 },
};
}
}
public class Highscore
{
public string Name { get; set; }
public int Score { get; set; }
}
public Highscore GetHighest()
{
return Highscores.OrderByDescending(o => o.Score).First();
}
I'm trying to deserialize a rest uri located at http://ws.geonames.org/countryInfo?lang=it&country=DE and keep getting error (There is an error in XML document (1, 1)). Plug http://ws.geonames.org/countryInfo?lang=it&country=DE into the browser and you can see the result.
I have a class
public class Country
{
public string CountryName {get;set;}
public string CountryCode {get;set;}
}
and the method in my console app is as follows:
static void DeserializeTheXML()
{
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "countryName";
xRoot.IsNullable = true;
XmlSerializer ser = new XmlSerializer(typeof(Country), xRoot);
XmlReader xRdr = XmlReader.Create(new StringReader("http://ws.geonames.org/countryInfo?lang=it&country=DE"));
Country tvd = new Country();
tvd = (Country)ser.Deserialize(xRdr);
Console.WriteLine("Country Name = " + tvd.CountryName);
Console.ReadKey();
}
any ideas on how to deserialize this rest service? thanks..
For serialization to work successfully you need to decorate your objects with the proper serialization attributes or use the XmlAttributeOverrides constructor. Also don't forget that XML is case sensitive and your objects must reflect the XML structure you are deserializing:
public class GeoNames
{
[XmlElement("country")]
public Country[] Countries { get; set; }
}
public class Country
{
[XmlElement("countryName")]
public string CountryName { get; set; }
[XmlElement("countryCode")]
public string CountryCode { get; set; }
}
class Program
{
static void Main()
{
var url = "http://ws.geonames.org/countryInfo?lang=it&country=DE";
var serializer = new XmlSerializer(typeof(GeoNames), new XmlRootAttribute("geonames"));
using (var client = new WebClient())
using (var stream = client.OpenRead(url))
{
var geoNames = (GeoNames)serializer.Deserialize(stream);
foreach (var country in geoNames.Countries)
{
Console.WriteLine(
"code: {0}, name: {1}",
country.CountryCode,
country.CountryName
);
}
}
}
}