Trying to deserialize json array - c#

I am trying to deserialize a local file in my project which is a json file. However I am getting this error with the current code:
"Unexpected character encountered while parsing value: G. Path '', line 0, position 0"
C# code
string filepath = Application.StartupPath + #"\city.list.json";
for(int i = 0; i< 40; i++)
{
foreach (string x in File.ReadLines(filepath))
{
if(x.Contains("id") || x.Contains("name"))
{
var data = JsonConvert.DeserializeObject<City.values>(filepath);
//City city = JsonConvert.DeserializeObject<City>(File.ReadAllText(filepath));
//cityList.Add(data.name, data.id);
}
else
{
}
}
}
class City
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class values
{
[JsonProperty(PropertyName = "id")]
public string id { get; set; }
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
}
}
Json file I am trying to deserialize from. This is just a quick sample taken out from the file. It is quite large ^^
[
{
"id":707860,
"name":"Hurzuf",
"country":"UA",
"coord":{
"lon":34.283333,
"lat":44.549999
}
},
{
"id":519188,
"name":"Novinki",
"country":"RU",
"coord":{
"lon":37.666668,
"lat":55.683334
}
},

You seem to have some huge misconceptions of how JSON deserializing works. First thing to address is you shouldn't be iterating through the lines of the json file. As pointed out in the comments, your JSON file is very large (~1.8 million lines) so your best bet is to use the JsonReader overload of DeserializeObject(), see Json.NET performance tips:
List<City.values> cities = new List<City.values>();
string filepath = Application.StartupPath + #"\city.list.json";
using (StreamReader sr = new StreamReader(filepath))
using (JsonReader reader = new JsonTextReader(sr))
{
JsonSerializer serializer = new JsonSerializer();
// read the json from a stream
// json size doesn't matter because only a small piece is read at a time from the HTTP request
cities = JsonConvert.DeserializeObject<List<City.values>>(reader);
}
Draw your attention to this line:
cities = JsonConvert.DeserializeObject<List<City.values>>(reader);
Here we leverage JSON.NET to deserialize. The difference between your code and the code I included here is that your JSON is a collection of objects, what this means is you need to deserialize into a collection of your City.values objects, in this case I used a List<T>.
Now we have a variable cities that is a collection of City.values objects that are included in your JSON.

Related

How to convert json format string to json in c#

Am getting json formatted string which is stored in database, now i want to convert it into json format. How can i convert it Please help.
var labelnames = #"{'LabelName':'LabelName1','IsHeader':true},{'LabelName':'LabelName2','IsHeader':false},{'LabelName':'LabelName3','IsHeader':true},{'LabelName':'LabelName4','IsHeader':false}";
I want to convert above code to proper json format
This is an invalid JSON format, moreover it does not have surrounding array brackets []. Ideally you should fix this at source.
You could do a simple replace
MyLabels = JsonConvert.DeserializeObject<List<Label>>(labelnames = "[" + labelnames.Replace("'", "\"") + "]")
However this may throw an error if any of the values also contain a '.
Therefore, you could create a custom JsonTextReader
using (var sw = new StringReader("[" + labelnames + "]"))
using (var reader = new MyJsonTextReader(sw))
{
JsonSerializer ser = new JsonSerializer();
MyLabels = ser.Deserialize<List<Label>>(reader);
}
class MyJsonTextReader : JsonTextReader
{
public override char QuoteChar { get; protected set; } = '\'';
public MyJsonTextReader(TextReader r) : base(r){}
}
class Label
{
public string LabelName;
public bool IsHeader;
}
dotnetfiddle

Add data to the json instead of overwriting it C#

So i have code that writes my data to a JSON with the library newtonsoft. But the problem now is that the JSON gets overwritten everytime instead of addes behind the previeous data.
Here is my code
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartArray();
writer.WriteStartObject();
writer.WritePropertyName("Temperature");
writer.WriteValue(temperature);
writer.WritePropertyName("Score");
writer.WriteValue(score);
writer.WritePropertyName("TrackId");
writer.WriteValue(trackId);
/*
writer.WriteStartObject();
writer.WritePropertyName("CPU");
writer.WriteValue("Intel");
writer.WritePropertyName("PSU");
writer.WriteValue("500W");
writer.WritePropertyName("Drives");
writer.WriteStartArray();
writer.WriteValue("DVD read/writer");
writer.WriteComment("(broken)");
writer.WriteValue("500 gigabyte hard drive");
writer.WriteValue("200 gigabyte hard drive");
writer.WriteEnd();
*/
writer.WriteEndObject();
writer.WriteEnd();
}
System.IO.File.WriteAllText(#"C:/Users/Kimeru/Documents/Dermalog Noah WPF/data.json", sb.ToString());
This is the result I want to achieve:
[
{
"Temperature": "24.6",
"Score": "37",
"TrackId": 3
}
,
{
"Temperature": "16.8",
"Score": "38",
"TrackId": 4
}
]
I'm pretty new to the .NET coding world so I'm trying my best to explain.
I think a better solution would be to:
Read json and convert to list of class object that represents the json objects
Add, modify or remove objects from the list
Serialize the list of class objects to json
Write the new json to the file
I made a little example:
public class TrackData
{
public double Temperature { get; set; }
public double Score { get; set; }
public int TrackId { get; set; }
}
public void WriteJson(string filePath, List<TrackData> trackDataList)
{
string json = JsonConvert.SerializeObject(trackDataList);
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(json);
}
}
public List<TrackData> ReadJson(string filePath)
{
using (StreamReader sr = new StreamReader(filePath))
{
string json = sr.ReadToEnd();
return JsonConvert.DeserializeObject<List<TrackData>>(json);
}
}
Now you can use the methods and class this way:
List<TrackData> myTrackDataList = ReadJson("Filepath");
TrackData newTrackData = new TrackData();
newTrackData.Score = 38;
newTrackData.Temperature = 22;
newTrackData.TrackId = 5;
myTrackDataList.Add(newTrackData);
WriteJson("FilePath", myTrackDataList);
You use System.IO.File.WriteAllText(); which overrides the existing file.
Simply use System.IO.File.AppendAllText(); to add your text to the file.
I dont think its good idea to add to a json file like this,
save each object into a new json file so you can read it after.
Path.GetTempFileName() should give you a unique file name
System.IO.File.WriteAllText($#"C:/Users/Kimeru/Documents/Dermalog Noah WPF/{Path.GetTempFileName()}_data.json", sb.ToString());
There are other ways to get unique file name generated for you
How to Generate unique file names in C#

CSV Helper saying item does not exist when it does

I am trying to use csv helper libary to parse my csv. But I am having an issue it says that the itemcode does not exist when its there in the file.
// Adding stock item code
Sage.Accounting.Stock.StockItem stockItem = new Sage.Accounting.Stock.StockItem();
string line = null;
public void ImportCsv(string filename)
{
TextReader reader = File.OpenText(filename);
var csv = new CsvReader(reader);
csv.Configuration.HasHeaderRecord = true;
csv.Read();
// Dynamic
// Using anonymous type for the class definition
var anonymousTypeDefinition = new
{
Itemcode = string.Empty,
Barcode = string.Empty
};
var records = csv.GetRecords(anonymousTypeDefinition);
}
This is the csv structure
"Itemcode","Barcode","description"
"P4S100001","303300054486","Test Product"
This is my first time using the csvhelper as showing here at https://joshclose.github.io/CsvHelper/
You are better off creating a strongly typed model to hold the data if one does not already exist
public class Item {
public string Itemcode { get; set; }
public string Barcode { get; set; }
public string description { get; set; }
}
and using GetRecords<T>() to read the records by type
TextReader reader = File.OpenText(filename);
var csv = new CsvReader(reader);
var records = csv.GetRecords<Item>();
Your GetRecords function needs a type specifier like so:
var records = csv.GetRecords<type>();
Also you may want to put csv.Read() in a while loop depending on your need.
Since all your values have quotes you need to specify it in the config. Working with quotes in csvHelper is frustrating. if not all if the values have quotes there are ways to handle that as well but not as nicely as this
var csv = new CsvReader(reader,new CsvHelper.Configuration.Configuration
{
HasHeaderRecord = true,
QuoteAllFields = true
});
var anonymousTypeDefinition = new
{
Itemcode = string.Empty,
Barcode = string.Empty
};
var records = csv.GetRecords(anonymousTypeDefinition);

Creating JSON from a CSV file in C#

First of all my apologies because this is going to be a "How to" question rather than a technical question. I have a CSV file as follows-
London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4
Now my plan is to create a JSON object from that CSV in the following format-
[
{
"From": "London",
"To": "Dubai",
"Duration": 4
},
{
"From": "Dubai",
"To": "Mumbai",
"Duration": 8
},
{
"From": "Dubai",
"To": "Dhaka",
"Duration": 4
},
]
How do I go about and do that? Currently I can load the CSV using OpenFileDialog but no idea what else I should do to get it done? Use Model Classes? JSON.Net? Please advice me and some code samples would be appreciated!
You can add csv records to a List<T> and then serialize it with Newtonsoft.Json to get your required JSON object. See the example below:
class Program
{
static void Main(string[] args)
{
string[] csv = new[] { "London,Dubai,4", "Dubai,Mumbai,8", "Dubai,Dhaka,4" };
List<model> list = new List<model>();
foreach (var item in csv)
{
string[] fields = item.Split(',');
list.Add(new model
{
From = fields[0],
To = fields[1],
Duration = fields[2]
});
}
var json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
Console.ReadLine();
}
}
public class model
{
public string From { get; set; }
public string To { get; set; }
public string Duration { get; set; }
}
You can use TextFieldParser from the Microsoft.VisualBasic.FileIO namespace and Microsoft.VisualBasic.dll assembly to parse CSV files. Despite the VisualBasic name the class is perfectly usable in c#.
First, add the following extension method:
public static class TextFieldParserExtensions
{
public static IEnumerable<string []> ReadAllFields(this TextFieldParser parser)
{
if (parser == null)
throw new ArgumentNullException();
while (!parser.EndOfData)
yield return parser.ReadFields();
}
}
Now you can use LINQ to transform each CSV line into an anonymous or named type for serialization, like so:
var csv = #"London,Dubai,4
Dubai,Mumbai,8
Dubai,Dhaka,4";
string json;
using (var stream = new StringReader(csv))
using (TextFieldParser parser = new TextFieldParser(stream))
{
parser.SetDelimiters(new string[] { "," });
var query = parser.ReadAllFields()
.Select(a => new { From = a[0], To = a[1], Duration = int.Parse(a[2]) });
json = new JavaScriptSerializer().Serialize(query);
}
Here I am using JavaScriptSerializer but the same code can be used with json.net
json = JsonConvert.SerializeObject(query, Formatting.Indented);
Be sure to evaluate the query before closing the TextFieldParser.
I Believe this should work for all different kinds of .csv files
Comments are in the code
public class Program
{
public static void Main(string[] args)
{
var list = new List<Dictionary<string, string>>();
Console.WriteLine("Put in the path to your .csv file");
var response1 = Console.ReadLine();
Console.WriteLine("Initializing...");
// Read All of the lines in the .csv file
var csvFile = File.ReadAllLines(response1);
// Get The First Row and Make Those You Field Names
var fieldNamesArray = csvFile.First().Split(',');
// Get The Amount Of Columns In The .csv
// Do the -1 so you can use it for the indexer below
var fieldNamesIndex = fieldNamesArray.Count() - 1;
// Skip The First Row And Create An IEnumerable Without The Field Names
var csvValues = csvFile.Skip(1);
// Iterate Through All Of The Records
foreach (var item in csvValues)
{
var newDiction = new Dictionary<string, string>();
for (int i = 0; i < fieldNamesIndex;)
{
foreach (var field in item.Split(','))
{
// Think Of It Like This
// Each Record Is Technically A List Of Dictionary<string, string>
// Because When You Split(',') you have a string[]
// Then you iterate through that string[]
// So there is your value but now you need the field name to show up
// That is where the Index will come into play demonstrated below
// The Index starting at 0 is why I did the -1 on the fieldNamesIndex variable above
// Because technically if you count the fields below its actually 6 elements
//
// 0,1,2,3,4,5 These Are The Field Names
// 0,1,2,3,4,5 These Are The Values
// 0,1,2,3,4,5
//
// So what this is doing is int i is starting at 0 for each record
// As long as i is less than fieldNamesIndex
// Then split the record so you have all of the values
// i is used to find the fieldName in the fieldNamesArray
// Add that to the Dictionary
// Then i is incremented by 1
// Add that Dictionary to the list once all of the values have been added to the dictionary
//
// Add the field name at the specified index and the field value
newDiction.Add(fieldNamesArray.ElementAt(i++), field);
}
list.Add(newDiction);
}
}
Console.WriteLine("Would You Like To Convert To Json Now?");
Console.WriteLine("[y] or [n]");
var response = Console.ReadLine();
if (response == "y")
{
Console.WriteLine("Where Do You Want The New File?");
var response2 = Console.ReadLine();
// Serialize the list into your Json
var json = JsonConvert.SerializeObject(list);
File.Create(response2).Dispose();
File.AppendAllText(response2, json);
Console.WriteLine(json);
Console.ReadLine();
}
else
{
Console.WriteLine("Ok See You Later");
Console.ReadLine();
}
}
}

C# Serializing datacontracts from file

I have a list of Xml messages specifically DataContract messages that i record to a file. And i am trying to deserialize them from file one by one. I do not want to read the whole file into memory at once because i expect it to be very big.
I have an implementation of this serialization and that works. I did this by serializing using a FileStream and reading the bytes and using regular expression to determine the end of element. Then taking the element and using DataContractSerializer to get the actual object.
But i was told I should be using higher level code to do this task and it seems like that should be possible. I have the following code that i think should work but it doesn't.
FileStream readStream = File.OpenRead(filename);
DataContractSerializer ds = new DataContractSerializer(typeof(MessageType));
MessageType msg;
while ((msg = (MessageType)ds.ReadObject(readStream)) != null)
{
Console.WriteLine("Test " + msg.Property1);
}
The above code is fed with an input file containing something along the following lines:
<MessageType>....</MessageType>
<MessageType>....</MessageType>
<MessageType>....</MessageType>
It appears that i can read and deserialize the first element correctly but after that it fails saying:
System.Runtime.Serialization.SerializationException was unhandled
Message=There was an error deserializing the object of type MessageType. The data at the root level is invalid. Line 1, position 1.
Source=System.Runtime.Serialization
I have read somewhere that it is due to the way DataContractSerializer works with padded '\0''s to the end - but i couldn't figure out how to fix this problem when reading from a stream without figuring out the end of MessageType tag in some other way. Is there another Serialization class that i should be using? or perhaps a way around this problem?
Thanks!
When you're deserializing the data from the file, WCF uses by default a reader which can only consume proper XML documents. The document which you're reading isn't - it contains multiple root elements, so it's effectively a fragment. You can change the reader the serializer is using by using another overload of ReadObject, as shown in the example below, to one which accepts fragments (by using the XmlReaderSettings object). Or you can have some sort of wrapping element around the <MessageType> elements, and you'd read until the reader were positioned at the end element for the wrapper.
public class StackOverflow_7760551
{
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
public override string ToString()
{
return string.Format("Person[Name={0},Age={1}]", this.Name, this.Age);
}
}
public static void Test()
{
const string fileName = "test.xml";
using (FileStream fs = File.Create(fileName))
{
Person[] people = new Person[]
{
new Person { Name = "John", Age = 33 },
new Person { Name = "Jane", Age = 28 },
new Person { Name = "Jack", Age = 23 }
};
foreach (Person p in people)
{
XmlWriterSettings ws = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
OmitXmlDeclaration = true,
Encoding = new UTF8Encoding(false),
CloseOutput = false,
};
using (XmlWriter w = XmlWriter.Create(fs, ws))
{
DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
dcs.WriteObject(w, p);
}
}
}
Console.WriteLine(File.ReadAllText(fileName));
using (FileStream fs = File.OpenRead(fileName))
{
XmlReaderSettings rs = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment,
};
XmlReader r = XmlReader.Create(fs, rs);
while (!r.EOF)
{
Person p = new DataContractSerializer(typeof(Person)).ReadObject(r) as Person;
Console.WriteLine(p);
}
}
File.Delete(fileName);
}
}
Maybe your file contains BOM
It's common for UTF-8 encoding
XmlSerializer xml = new XmlSerializer(typeof(MessageType));
XmlDocument xdoc = new XmlDocument();
xdoc.Load(stream);
foreach(XmlElement elm in xdoc.GetElementsByTagName("MessageType"))
{
MessageType mt = (MessageType)xml.Deserialize(new StringReader(elm.OuterXml));
}

Categories

Resources