I need to produce excel sheet from JSON object.
My JSON object is unknown and can be different from call to call. It have a simple structure (same fields in multiple rows).
I want to use the following code.
workSheet.Cells[2, 1].LoadFromCollection(dataList, false);
dataList input is List (dynamic)
Since my JSON is unknown, I can't define a class for this list (params names and types)
My question is How do I convert a JSON object dynamically to List?
for example I have json object with 3 rows to export:
dataJson -> [{"FirstName":"Yaniv","LastName":"Test","Age": 30,"SubmitDate":"2019-10-04"},{....},{....}]
I need it to be a List dataList -> Count 3
first Item:
Age 30
FirstName "Yaniv"
LastName "Test"
SubmitDate [2019-10-04]
You could deserialise your JSON into a List<Dictionary<string, object>>. For example:
var json = "[{\"FirstName\":\"Yaniv\",\"LastName\":\"Test\",\"Age\": ......]";
var data = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(json);
Now you can extract some details from this list. So to get the column names:
var columnNames = data.First().Keys.ToList();
And loop around your data like this. This will basically output in CSV format, but it should be enough to modify for your needs:
// Write out the column headers
foreach (var columnName in columnNames)
{
Console.Write(columnName + ",");
}
Console.WriteLine();
// Write out each element
foreach (var item in data)
{
foreach (var columnName in columnNames)
{
Console.Write(item[columnName] + ",");
}
Console.WriteLine();
}
This will give output something like this:
FirstName,LastName,Age,SubmitDate,
Yaniv,Test,30,2019-10-04,
Yaniv,Test,30,2019-10-04,
Yaniv,Test,30,2019-10-04,
If you're using Newtonsoft.Json you can deserialize it into a dynamic structure:
var dyn = JArray.Parse("{jsonhere...}");
Then you can read properties like that:
const string json =
"[{\"prop\": 1, \"test\": \"test!\"}, {\"prop\": 2, \"test\": \"test again!\"}, {\"prop\": 3, \"test\": \"one more!\"}]";
var parsed = JArray.Parse(json);
foreach (var value in parsed)
{
var prop = value.Value<int>("prop");
var test = value.Value<string>("test");
Console.WriteLine($"Prop: [{prop}] | Test: [{test}]");
}
Result output will be:
Prop: [1] | Test: [test!]
Prop: [2] | Test: [test again!]
Prop: [3] | Test: [one more!]
Producing excel from JSON input by LoadFromCollection was a bad idea.
The simplest and easiest solution is LoadFromDataTable by convert the JSON to a DataTable:
DataTable data = Newtonsoft.Json.JsonConvert.DeserializeObject<DataTable>(dataJson);
workSheet.Cells[1, 1].LoadFromDataTable(data,true);
Simple as that 😉
Related
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);
}
I'm using the FileHelpers DelimitedClassBuilder to build a class based on metadata in a datatable. This way I can read any file known in the metadata. I read it as a stream and process each record individually. For further processing I want to add some fields to the data and then serialize it to JSON. It's the adding of fields part that doesn't work. The stream returns an object. I'm using a work-around. Serializing the object to JSON, de-serializing it to a dictionary, adding the fields and then serializing it to JSON again. I'm sure this can be done in a more efficient way. I tried converting it to a list but that doesn't work.
//build runtime class based on metadata
FD.DelimitedClassBuilder cb = new FD.DelimitedClassBuilder("ImportFile", "|");
cb.IgnoreFirstLines = 1;
foreach (DT.DataRow drMetadata in dtMetadata.Rows)
{
cb.AddField(drMetadata["EntityColumnName"].ToString(), typeof(string));
cb.LastField.FieldQuoted = true;
cb.LastField.QuoteMode = FH.QuoteMode.AlwaysQuoted;
cb.LastField.QuoteMultiline = FH.MultilineMode.AllowForBoth;
}
//create async filehelper engine for row by row processing
FH.FileHelperAsyncEngine fhe = new FH.FileHelperAsyncEngine(cb.CreateRecordClass());
using (fhe.BeginReadStream(file))
{
foreach(object record in fhe)
{
//convert object to list, doesn't work
//SG.List<object> blaat = (record as SG.IEnumerable<object>).Cast<object>().ToList();
//serialize record class to json
string json = JS.JsonConvert.SerializeObject(record, JS.Formatting.Indented);
//convert message to key-value dictionary
SG.IDictionary<string, string> values = JS.JsonConvert.DeserializeObject<SG.IDictionary<string, string>>(json);
values.Add("SourceSystem", messagesource);
values.Add("SourceType", messagetype);
string json2 = JS.JsonConvert.SerializeObject(values, JS.Formatting.Indented);
SY.Console.WriteLine(json2);
}
}
fhe.Close();
You can use a list of fields obtained via reflection on the record class. Then use Linq's ToDictionary to populate your values.
var recordClass = cb.CreateRecordClass();
List<FieldInfo> fields = recordClass.GetFields().ToList();
FileHelperAsyncEngine fhe = new FileHelperAsyncEngine(recordClass);
using (fhe.BeginReadStream(file))
{
foreach (var record in fhe)
{
IDictionary<string, object> values = fields.ToDictionary(x => x.Name, x => x.GetValue(record));
values.Add("SourceSystem", "messagesource");
values.Add("SourceType", "messagetype");
string json = JsonConvert.SerializeObject(values, Formatting.Indented);
Console.WriteLine(json);
}
}
I have thousands of lines of data in a text file I want to make easily searchable by turning it into something easier to search (I am hoping an XML or another type of large data structure, though I am not sure if it will be the best for what I have in mind).
The data looks like this for each line:
Book 31, Thomas,George, 32, 34, 154
(each book is not unique, they are indexes so book will have several different entries of whom is listed in it, and the numbers are the page they are listed)
So I am kinda of lost on how to do this, I would want to read the .txt file, trim out all the spaces and commas, I basically get how to prep the data for it, but how would I programmatically make that many elements and values in xml or populate some other large data structure?
If your csv file does not change too much and the structure is stable, you could simply parse it to a list of objects at startup
private class BookInfo {
string title {get;set;}
string person {get;set;}
List<int> pages {get;set;}
}
private List<BookInfo> allbooks = new List<BookInfo>();
public void parse() {
var lines = File.ReadAllLines(filename); //you could also read the file line by line here to avoid reading the complete file into memory
foreach (var l in lines) {
var info = l.Split(',').Select(x=>x.Trim()).ToArray();
var b = new BookInfo {
title = info[0],
person = info[1]+", " + info[2],
pages = info.Skip(3).Select(x=> int.Parse(x)).ToList()
};
allbooks.Add(b);
}
}
Then you can easily search the allbooks list with for instance LINQ.
EDIT
Now, that you have clarified your input, I adapted the parsing a little bit to better fit your needs.
If you want to search your booklist by either the title or the person more easily, you can also create a lookup on each of the properties
var titleLookup = allbooks.ToLookup(x=> x.title);
var personLookup = allbooks.ToLookup(x => x.person);
So personLookup["Thomas, George"] will give you a list of all bookinfos that mention "Thomas, George" and titleLookup["Book 31"] will give you a list of all bookinfos for "Book 31", ie all persons mentioned in that book.
If you want the CSV file to make easily searchable by turning it into something easier to search, you can convert it to DataTable.
if you want data , you can use LINQ to XML to search
The following class generates both DataTable or Xml data format. You can pass delimeter ,includeHeader or use the default:
class CsvUtility
{
public DataTable Csv2DataTable(string fileName, bool includeHeader = false, char separator = ',')
{
IEnumerable<string> reader = File.ReadAllLines(fileName);
var data = new DataTable("Table");
var headers = reader.First().Split(separator);
if (includeHeader)
{
foreach (var header in headers)
{
data.Columns.Add(header.Trim());
}
reader = reader.Skip(1);
}
else
{
for (int index = 0; index < headers.Length; index++)
{
var header = "Field" + index; // headers[index];
data.Columns.Add(header);
}
}
foreach (var row in reader)
{
if (row != null) data.Rows.Add(row.Split(separator));
}
return data;
}
public string Csv2Xml(string fileName, bool includeHeader = false, char separator = ',')
{
var dt = Csv2DataTable(fileName, includeHeader, separator);
var stream = new StringWriter();
dt.WriteXml(stream);
return stream.ToString();
}
}
example to use:
CsvUtility csv = new CsvUtility();
var dt = csv.Csv2DataTable("f1.txt");
// Search for string in any column
DataRow[] filteredRows = dt.Select("Field1 LIKE '%" + "Thomas" + "%'");
//search in certain field
var filtered = dt.AsEnumerable().Where(r => r.Field<string>("Field1").Contains("Thomas"));
//generate xml
var xml= csv.Csv2Xml("f1.txt");
Console.WriteLine(xml);
/*
output of xml for your sample:
<DocumentElement>
<Table>
<Field0>Book 31</Field0>
<Field1> Thomas</Field1>
<Field2>George</Field2>
<Field3> 32</Field3>
<Field4> 34</Field4>
<Field5> 154</Field5>
</Table>
</DocumentElement>
*/
I have a JSON data ( http://country.io/names.json ) like :
{"BD": "Bangladesh", "BE": "Belgium", "BF": "Burkina Faso", "BG": "Bulgaria", "BA": "Bosnia and Herzegovina", "BB": "Barbados" }
I want to list that json like CountryCode-CountryName (BD-Bangladesh) . How do I do that on windows form app. ?
You could deserialise the JSON into a Dictionary instead of a single object. This gives you access to all the codes and names, like so:
var json = #"{""BD"": ""Bangladesh"", ""BE"": ""Belgium"", ""BF"": ""Burkina Faso"", ""BG"": ""Bulgaria"", ""BA"": ""Bosnia and Herzegovina"", ""BB"": ""Barbados"" }";
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
foreach (var item in dict)
{
var countryCode = item.Key;
var countryName = item.Value;
// do whatever you want to do with those two values here
Console.WriteLine("CountryCode: {0} CountryName: {1}", countryCode, countryName);
}
In that code it simply writes it to the screen, but obviously once you have that loop in place you can do whatever you like with the country code and name.
I am trying to read in POST data to an ASPX (c#) page. I have got the post data now inside a string. I am now wondering if this is the best way to use it. Using the code here (http://stackoverflow.com/questions/10386534/using-request-getbufferlessinputstream-correctly-for-post-data-c-sharp) I have the following string
<callback variable1="foo1" variable2="foo2" variable3="foo3" />
As this is now in a string, I am splitting based on a space.
string[] pairs = theResponse.Split(' ');
Dictionary<string, string> results = new Dictionary<string, string>();
foreach (string pair in pairs)
{
string[] paramvalue = pair.Split('=');
results.Add(paramvalue[0], paramvalue[1]);
Debug.WriteLine(paramvalue[0].ToString());
}
The trouble comes when a value has a space in it. For example, variable3="foo 3" upsets the code.
Is there something better I should be doing to parse the incoming http post variables within the string??
You might want to treat it as XML directly:
// just use 'theResponse' here instead
var xml = "<callback variable1=\"foo1\" variable2=\"foo2\" variable3=\"foo3\" />";
// once inside an XElement you can get all the values
var ele = XElement.Parse(xml);
// an example of getting the attributes out
var values = ele.Attributes().Select(att => new { Name = att.Name, Value = att.Value });
// or print them
foreach (var attr in ele.Attributes())
{
Console.WriteLine("{0} - {1}", attr.Name, attr.Value);
}
Of course you can change that last line to whatever you want, the above is a rough example.