Exporting mutiline data into same cell in csv - c#

I understand that this question have been asked many times (1, 2 & 3) but I just don't understand how to apply it in my case. I have tried playing around for hours but I cannot get it right.
I have variables in the form of List<string>where each list contain datas that have line breaks between them/multiline data. Then I called an event that would export these datas in a CSV file. Below is my code.
savestate.cs - class where I initialized the variables
public partial class Savestate
{
public static List<string> rtb1_list = new List<string>();
public static List<string> rtb2_list = new List<string>();
public static List<string> rtb3_list = new List<string>();
public static List<string> rtb4_list = new List<string>();
}
Form1.cs - The event
public void Savetocsv()
{
Type s = typeof(Savestate);
FieldInfo[] fields = s.GetFields(BindingFlags.Public | BindingFlags.Static);
StringBuilder csvdata = new StringBuilder();
string header = String.Join(",", fields.Select(f => f.Name).ToArray());
csvdata.AppendLine(header);
string rtb1 = String.Join(",", Savestate.rtb1_list.ToArray());
string rtb2 = String.Join(",", Savestate.rtb2_list.ToArray());
string rtb3 = String.Join(",", Savestate.rtb3_list.ToArray());
string rtb4 = String.Join(",", Savestate.rtb4_list.ToArray());
string newlinestring = string.Format("{0}; {1}; {2}; {3}", rtb1, rtb2, rtb3, rtb4);
csvdata.AppendLine(newlinestring);
string filepath = #"C:\new.csv";
File.WriteAllText(filepath, csvdata.ToString());
}
However when I opened the CSV file, the words are all over the place. For example I wrote hi then a new line then I wrote bye. This is the actual output and this is my intended output.Hope that I can get help.

To insert line breaks in csv file you need to surround string with double quotes, so desired output is generated by following code :
public partial class Savestate
{
public static List<string> rtb1_list = new List<string>() { "hi1", "bye1" };
public static List<string> rtb2_list = new List<string>() { "hi2", "bye2" };
public static List<string> rtb3_list = new List<string>() { "hi3", "bye3" };
public static List<string> rtb4_list = new List<string>() { "hi4", "bye4" };
}
public static void Savetocsv()
{
Type s = typeof(Savestate);
FieldInfo[] fields = s.GetFields(BindingFlags.Public | BindingFlags.Static);
StringBuilder csvdata = new StringBuilder();
string header = String.Join(",", fields.Select(f => f.Name).ToArray());
csvdata.AppendLine(header);
string rtb1 = String.Join("\n", Savestate.rtb1_list.ToArray());
string rtb2 = String.Join("\n", Savestate.rtb2_list.ToArray());
string rtb3 = String.Join("\n", Savestate.rtb3_list.ToArray());
string rtb4 = String.Join("\n", Savestate.rtb4_list.ToArray());
string newlinestring = string.Format("\"{0}\",\" {1}\",\" {2}\",\" {3}\"", #rtb1, #rtb2, #rtb3, #rtb4);
csvdata.AppendLine(newlinestring);
string filepath = #"new.csv";
File.WriteAllText(filepath, csvdata.ToString());
}
Output file:

I suggest using CsvHelper Nuget Package when dealing with CSV, then try doing the following, I added an extension method to print each rtb list as one string:
public partial class Savestate
{
public static List<string> rtb1_list = new List<string>() { "hi", "bye" };
public static List<string> rtb2_list = new List<string>() { "hi", "bye" };
public static List<string> rtb3_list = new List<string>() { "hi", "bye" };
public static List<string> rtb4_list = new List<string>() { "hi", "bye" };
}
public static class SavestateExtensions
{
public static string GetRtbListAsString(this IEnumerable<string> rtb_list)
{
StringBuilder str = new StringBuilder();
foreach (var value in rtb_list)
{
str.AppendLine(value);
}
return str.ToString();
}
}
Then use the CsvWriter from CSVHelper:
using (var writer = new StreamWriter("file.csv"))
{
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.Delimiter = ";";
csvWriter.Configuration.Encoding = Encoding.UTF8;
csvWriter.WriteField("rtb1_list ");
csvWriter.WriteField("rtb2_list ");
csvWriter.WriteField("rtb3_list ");
csvWriter.WriteField("rtb4_list ");
csvWriter.NextRecord();
csvWriter.WriteField(Savestate.rtb1_list.GetRtbListAsString());
csvWriter.WriteField(Savestate.rtb2_list.GetRtbListAsString());
csvWriter.WriteField(Savestate.rtb3_list.GetRtbListAsString());
csvWriter.WriteField(Savestate.rtb4_list.GetRtbListAsString());
csvWriter.NextRecord();
}
}
The output should be as the following:

Related

How to convert string[] to List<UserType>, using linq?

// Example: path = "C:\Users\MSI\Desktop\1.jpg"
There is an array and list:
string[] files = new string[] {"path1", "path2", "path3"};
List<UserType> mainFileList = new List<UserType>();
I don't want to describe the whole loop (for, foreach, ...) every time, I want to convert data from string[] to List in short form. How to do it using Linq?
public class UserType{
// Public fields
public readonly string FullPath;
public readonly string Name;
public UserType() { }
public UserType(string fullPath) {
FullPath = fullPath;
Name = Path.GetFileName(fullPath);
}
}
You can use LINQ:
string[] files = new string[] {"path1", "path2", "path3"};
List<UserType> mainFileList = files.Select(f => new UserType(f)).ToList();
But actually, there will still be a loop, which is now hidden in the Select method.

How to map any csv file to object with 1 method

I'm trying to map CSV file into class object with C#. My problem is that i have 3 different files, but I want to fallow DRY principles. Can someone tell me how to change 'ParseLine' method to make it possible?
C# consol app.
This is how my FileReader looks like:
public class FileReader<T> : IFileReader<T> where T : Entity
{
private readonly ITransactionReader<T> _transactionReader;
public FileReader(ITransactionReader<T> transactionReader)
{
_transactionReader = transactionReader;
}
public List<T> GetInfoFromFile(string filePath)
{
var lines = File.ReadAllLines(filePath);
var genericLines = new List<T>();
foreach (var line in lines)
{
genericLines.Add(_transactionReader.ParseLine(line));
}
return genericLines;
}
}
public interface IFileReader<T> where T : Entity
{
List<T> GetInfoFromFile(string filePath);
}
This is how the object should look like.
public class TransactionReader : ITransactionReader<Transaction>
{
public Transaction ParseLine(string line)
{
var fields = line.Split(";");
var transaction = new Transaction()
{
Id = fields[0],
Month = int.Parse(fields[1]),
Day = int.Parse(fields[2]),
Year = int.Parse(fields[3]),
IncomeSpecification = fields[4],
TransactionAmount = int.Parse(fields[5])
};
return transaction;
}
}
public interface ITransactionReader<T>
{
T ParseLine(string line);
}
This is how I run it for test purposes.
class Program
{
private static readonly string filePath = "C:/Users/<my_name>/Desktop/C# Practice/ERP/ERP/CsvFiles/Transaction.csv";
static void Main(string[] args)
{
ITransactionReader<Transaction> transactionReader = new TransactionReader();
IFileReader<Transaction> fileReader = new FileReader<Transaction>(transactionReader);
List<Transaction> Test()
{
var obj = fileReader.GetInfoFromFile(filePath);
return obj;
}
var list = Test();
}
}
I'm looking to modify that line:
genericLines.Add(_transactionReader.ParseLine(line));
and method arguments to make it open for any CSV fil.
I don't mind to change that composition into something more effective.

How to export JSON string to CSV file?

I have ASP.Net site. I have JSON string that need to exported to physical CSV file.
private String JsonToCsv(string jsonData, string delimiter)
{
try
{
StringWriter swObj = new StringWriter();
using (var csv = new CsvWriter(swObj))
{
csv.Configuration.SkipEmptyRecords = true;
csv.Configuration.WillThrowOnMissingField = false;
csv.Configuration.Delimiter = delimiter;
using (var dt = jsonStringToTable(jsonData))
{
foreach (DataColumn col in dt.Columns)
{
csv.WriteField(col.ColumnName);
}
csv.NextRecord();
foreach(DataRow row in dt.Rows)
{
for (var i = 0; i < dt.Columns.Count; i++)
{
csv.WriteField(row[i]);
}
csv.NextRecord();
}
}
}
return swObj.ToString();
}
catch (Exception ex)
{
//handle exception
return null;
}
}
private DataTable jsonStringToTable(string jsonContent)
{
DataTable dt = JsonConvert.DeserializeObject<DataTable>(jsonContent);
return dt;
}
public HttpResponseMessage ExportToCSV(string jsonData)
{
string csv = JsonToCsv(jsonData, ",");
HttpResponseMessage res = new HttpResponseMessage(HttpStatusCode.OK);
res.Content = new StringContent(csv);
res.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
res.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "export.csv" };
return res;
}
But neither I am getting any exception nor CSV file is getting any data.
The Export.csv is located in the root folder.
How do I export the JSON & auto download the file??
It seems you do have an error, that you are suppressing in your catch.
Your first error is in that your jsonContent is not actually json. You have a variable assignment jsonContent = [...] in your sample. the section [...] is your actual json.
to handle that, you need only compose it better, by not having it assign to a variable (recommended approach), or handle instances here with jsonContent.Split(new [] {'='}).Last(). (a declarative vs imperative approach/strategy).
Also, you are attempting to deserialize into an incorrect type, for it does not reflect your json data structure.
although there are other manners to convert and process one string to another. I do agree the proper thing to do here is to deserialize your object (or not serialize beforehand - recommended).
I'm providing a sample Console Application for you to review two implementations of handle a JsonToCsv operation.
dynamic (imperative)
and providing a Type and using System.Reflection on that type. (declarative to the Json.Convert.DeserializeObject<T>() method, imperative afterward)
there is a dependency on NewtonSoft.Json Assembly (Install it via NuGet package) in this implementation; it reflects your provided code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.Reflection;
using Newtonsoft;
namespace JsonToCsvTests
{
using Newtonsoft.Json;
using System.IO;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
TestJsonToCsv();
Console.ReadLine();
}
static void TestJsonToCsv()
{
string jsonData = #"jsonData = [
{
""DocumentName"": ""Test Document"",
""ActionDate"": ""2015-09-25T16:06:25.083"",
""ActionType"": ""View"",
""ActionPerformedBy"": ""Sreeja SJ""
},
{
""DocumentName"": ""Test Document"",
""ActionDate"": ""2015-09-25T16:12:02.497"",
""ActionType"": ""View"",
""ActionPerformedBy"": ""Sreeja SJ""
},
{
""DocumentName"": ""Test Document"",
""ActionDate"": ""2015-09-25T16:13:48.013"",
""ActionType"": ""View"",
""ActionPerformedBy"": ""Sreeja SJ""
}]";
Console.WriteLine("...using System.Dynamic and casts");
Console.WriteLine();
Console.WriteLine(JsonToCsv(jsonData, ","));
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("...using a provided StrongType with System.Reflection.");
Console.WriteLine();
Console.WriteLine(JsonToCsv<JsonData>(jsonData, ","));
}
static private string JsonToCsv(string jsonContent, string delimiter)
{
var data = jsonStringToTable(jsonContent);
var headers = ((IEnumerable<dynamic>)((IEnumerable<dynamic>)data).First()).Select((prop) => prop.Name).ToArray();
var csvList = new List<string>
{
string.Join(delimiter, headers.Select((prop) => string.Format(#"""{0}""", prop)).ToArray())
};
var lines = ((IEnumerable<dynamic>)data)
.Select(row => row)
.Cast<IEnumerable<dynamic>>()
.Select((instance) => string.Join(delimiter, instance.Select((v) => string.Format(#"""{0}""", v.Value))))
.ToArray();
csvList.AddRange(lines);
return string.Join(Environment.NewLine, csvList );
}
static private string JsonToCsv<T>(string jsonContent, string delimiter) where T : class
{
var data = jsonStringToTable<T>(jsonContent);
var properties = data.First().GetType().GetProperties();
var lines = string.Join(Environment.NewLine,
string.Join(delimiter, properties.Select((propInfo) => string.Format(#"""{0}""", propInfo.Name))),
string.Join(Environment.NewLine, data.Select((row) => string.Join(delimiter, properties.Select((propInfo) => string.Format(#"""{0}""", propInfo.GetValue(row)))))));
return lines;
}
static private dynamic jsonStringToTable(string jsonContent)
{
var json = jsonContent.Split(new[] { '=' }).Last();
return JsonConvert.DeserializeObject<dynamic>(json);
}
static private IEnumerable<T> jsonStringToTable<T>(string jsonContent) where T : class
{
var json = jsonContent.Split(new[] { '=' }).Last();
return JsonConvert.DeserializeObject<IEnumerable<T>>(json);
}
public class JsonData
{
public string DocumentName { get; set; }
public DateTime ActionDate { get; set; }
public string ActionType { get; set; }
public string ActionPerformedBy { get; set; }
}
}
}
Console.Output
...using System.Dynamic and casts
"DocumentName","ActionDate","ActionType","ActionPerformedBy"
"Test Document","9/25/2015 4:06:25 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:12:02 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:13:48 PM","View","Sreeja SJ"
...using a provided StrongType with System.Reflection.
"DocumentName","ActionDate","ActionType","ActionPerformedBy"
"Test Document","9/25/2015 4:06:25 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:12:02 PM","View","Sreeja SJ"
"Test Document","9/25/2015 4:13:48 PM","View","Sreeja SJ"
This is what i use to generate CSV file on my ASP.NET Website
public static class CSVUtils
{
public static void AddCsvLine(bool isFrenchSeparator, StringBuilder csv, params object[] values)
{
foreach (var value in values)
{
csv.Append('"').Append(value).Append('"');
if (isFrenchSeparator)
{
csv.Append(';');
}
else
{
csv.Append(',');
}
}
csv.Append('\r'); // AppendLine() adds a double line break with UTF32Encoding
}
}
public FileContentResult ExportCSV()
{
StringBuilder csv = new StringBuilder();
CSVUtils.AddCsvLine(false, csv, "Field1", "Field2", "Field3");
CSVUtils.AddCsvLine(false, csv, "value1", "value2", "value3");
return this.File(new UTF32Encoding().GetBytes(csv.ToString()), "text/csv", "myfile.csv");
}
I basically call the ExportCSV action from my website, on a button click for example and it downloads the file. Make sure to clean your JSON beforehand from all coma otherwise it would mess your CSV file.
EDIT: Specifically for JSON, you'd also have to anti-slash every " otherwise it would mess the StringBuilder i guess

How to convert Telerik ORM entity list to csv file

Is there easier way to convert telerik orm entity list to csv format?
The following simple static class will help you in this task. Note that it will create a .csv file, which contains the values of the entity's properties without taking into account the navigation properties:
public static partial class EntitiesExporter
{
public static void ExportEntityList<T>(string fileLocation, IEnumerable<T> entityList, string seperator = " , ")
{
string content = CreateFileContent<T>(entityList, seperator);
SaveContentToFile(fileLocation, content);
}
private static string CreateFileContent<T>(IEnumerable<T> entityList, string seperator)
{
StringBuilder result = new StringBuilder();
List<PropertyInfo> properties = new List<PropertyInfo>();
foreach (PropertyInfo item in typeof(T).GetProperties())
{
if (item.CanWrite)
{
properties.Add(item);
}
}
foreach (T row in entityList)
{
var values = properties.Select(p => p.GetValue(row, null));
var line = string.Join(seperator, values);
result.AppendLine(line);
}
return result.ToString();
}
private static void SaveContentToFile(string fileLocation, string content)
{
using (StreamWriter writer = File.CreateText(fileLocation))
{
writer.Write(content);
writer.Close();
}
}
}
You can consume the class like this in your code:
using (EntitiesModel dbContext = new EntitiesModel())
{
IQueryable<Category> cats = dbContext.Categories;
string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string fileLocation = Path.Combine(appDir, "test.csv");
EntitiesExporter.ExportEntityList<Category>(fileLocation, cats);
}
I hope this helps.

C# XML Serialization of an array - Skip "empty" string values

I want to skip the empty element creation in XML file during the xml Serialization in C#.
Ex :
ArrayElements elm = new ArrayElements
{ Items =new string[] "Item1", " ", "Item2", " ", " ", "Items" } };
During the serialization it should skip the empty strings.
This is my class :
[Serializable]
public class ArrayElements
{
[XmlElement(IsNullable=false)]
public string[] Items { get; set; }
}
You can do it with a surrogate property.
namespace Cheeso.Xml.Samples.Arrays
{
static class Extensions
{
private static XmlSerializerNamespaces _ns;
static Extensions()
{
// to suppress unused default namespace entries in the root elt
_ns = new XmlSerializerNamespaces();
_ns.Add( "", "" );
}
public static string SerializeToString(this XmlSerializer s, object o)
{
var builder = new System.Text.StringBuilder();
var settings = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
using ( var writer = System.Xml.XmlWriter.Create(builder, settings))
{
s.Serialize(writer, o, _ns);
}
return builder.ToString();
}
}
[XmlType("ArrayOfString")]
public class MyContainer
{
[XmlIgnore]
public String[] a;
// surrogate property
[XmlElement("string")]
public String[] A
{
get
{
List<String> _proxy = new List<String>();
foreach (var s in a)
{
if (!String.IsNullOrEmpty(s))
_proxy.Add(s);
}
return _proxy.ToArray();
}
set
{
a = value;
}
}
}
class StringArrayOnlyNonEmptyItems
{
static void Main(string[] args)
{
try
{
Console.WriteLine("\nRegular Serialization of an array of strings with some empty elements:");
String[] x = { "AAA", "BBB", "", "DDD", "", "FFF" };
XmlSerializer s1 = new XmlSerializer(typeof(String[]));
string s = s1.SerializeToString(x);
Console.WriteLine(s);
Console.WriteLine("\nSerialization of an array of strings with some empty elements, via a Container:");
MyContainer c = new MyContainer();
c.a = x;
XmlSerializer s2 = new XmlSerializer(typeof(MyContainer));
s = s2.SerializeToString(c);
Console.WriteLine(s);
}
catch (System.Exception exc1)
{
Console.WriteLine("uncaught exception:\n{0}", exc1);
}
}
}
}
Are you sure this is what you want? One drawback, is that when you deserialize, you will not be able to get back the empty strings, since there's no way for the deserializer to know about them. Usually when you deserialize, you want to get back an instance that looks exactly like the one you originally serialized.
If that is what you want, then you have to tweak your object to suit the serialization process. As Cheeso suggests, a surrogate property is a good solution for this.
Also, just for clarity, am I correct to say you have an object ArrayElements that has a property Items, which is an array of strings?

Categories