Getting data from HTML table into a datatable - c#

Ok so I need to query a live website to get data from a table, put this HTML table into a DataTable and then use this data. I have so far managed to use Html Agility Pack and XPath to get to each row in the table I need but I know there must be a way to parse it into a DataTable. (C#) The code I am currently using is:
string htmlCode = "";
using (WebClient client = new WebClient())
{
htmlCode = client.DownloadString("http://www.website.com");
}
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlCode);
//My attempt at LINQ to solve the issue (not sure where to go from here)
var myTable = doc.DocumentNode
.Descendants("table")
.Where(t =>t.Attributes["summary"].Value == "Table One")
.FirstOrDefault();
//Finds all the odd rows (which are the ones I actually need but would prefer a
//DataTable containing all the rows!
foreach (HtmlNode cell in doc.DocumentNode.SelectNodes("//tr[#class='odd']/td"))
{
string test = cell.InnerText;
//Have not gone further than this yet!
}
The HTML table on the website I am querying looks like this:
<table summary="Table One">
<tbody>
<tr class="odd">
<td>Some Text</td>
<td>Some Value</td>
</tr>
<tr class="even">
<td>Some Text1</td>
<td>Some Value1</td>
</tr>
<tr class="odd">
<td>Some Text2</td>
<td>Some Value2</td>
</tr>
<tr class="even">
<td>Some Text3</td>
<td>Some Value3</td>
</tr>
<tr class="odd">
<td>Some Text4</td>
<td>Some Value4</td>
</tr>
</tbody>
</table>
I'm not sure whether it is better/easier to use LINQ + HAP or XPath + HAP to get the desired result, I tried both with limited success as you can probably see. This is the first time I have ever made a program to query a website or even interact with a website in any way so I am very unsure at the moment! Thanks for any help in advance :)

Using some of Jack Eker's code above and some code from Mark Gravell (see post here) , I managed to come with a solution.
This code snippet is used to obtain the public holidays for the year of 2012 in South Africa as of writing this article
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Web;
using System.Net;
using HtmlAgilityPack;
namespace WindowsFormsApplication
{
public partial class Form1 : Form
{
private DataTable dt;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string htmlCode = "";
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.UserAgent, "AvoidError");
htmlCode = client.DownloadString("http://www.info.gov.za/aboutsa/holidays.htm");
}
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlCode);
dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(string));
int count = 0;
foreach (HtmlNode table in doc.DocumentNode.SelectNodes("//table"))
{
foreach (HtmlNode row in table.SelectNodes("tr"))
{
if (table.Id == "table2")
{
DataRow dr = dt.NewRow();
foreach (var cell in row.SelectNodes("td"))
{
if ((count % 2 == 0))
{
dr["Name"] = cell.InnerText.Replace(" ", " ");
}
else
{
dr["Value"] = cell.InnerText.Replace(" ", " ");
dt.Rows.Add(dr);
}
count++;
}
}
}
dataGridView1.DataSource = dt;
}
}
}
}

There's no such method out of the box from the HTML Agility Pack, but it shouldn't be too hard to create one. There's samples out there that do XML to Datatable from Linq-to-XML. These can be re-worked into what you need.
If needed I can help out creating the whole method, but not today :).
See also:
HTML Agility pack - parsing tables
parsing html with HTMLAGILITYPACK and loading into datatable C#

This is my solution. May be a bit messy but it is working perfectly at the moment :D
string htmlCode = "";
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.UserAgent, "AvoidError");
htmlCode = client.DownloadString("http://www.website.com");
}
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(htmlCode);
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(decimal));
int count = 0;
decimal rowValue = 0;
bool isDecimal = false;
foreach (var row in doc.DocumentNode.SelectNodes("//table[#summary='Table Name']/tbody/tr"))
{
DataRow dr = dt.NewRow();
foreach (var cell in row.SelectNodes("td"))
{
if ((count % 2 == 0))
{
dr["Name"] = cell.InnerText.Replace(" ", " ");
}
else
{
isDecimal = decimal.TryParse((cell.InnerText.Replace(".", "")).Replace(",", "."), out rowValue);
if (isDecimal)
{
dr["Value"] = rowValue;
}
dt.Rows.Add(dr);
}
count++;
}
}

Simple logic to convert a htmltable to datatable :
//Define your webtable
public static HtmlTable table
{
get
{
HtmlTable var = new HtmlTable(parent);
var.SearchProperties.Add("id", "searchId");
return var;
}
}
//Convert a webtable to datatable
public static DataTable getTable
{
get
{
DataTable dtTable= new DataTable("TableName");
UITestControlCollection rows = table.Rows;
UITestControlCollection headers = rows[0].GetChildren();
foreach (HtmlHeaderCell header in headers)
{
if (header.InnerText != null)
dtTable.Columns.Add(header.InnerText);
}
for (int i = 1; i < rows.Count; i++)
{
UITestControlCollection cells = rows[i].GetChildren();
string[] data = new string[cells.Count];
int counter = 0;
foreach (HtmlCell cell in cells)
{
if (cell.InnerText != null)
data[counter] = cell.InnerText;
counter++;
}
dtTable.Rows.Add(data);
}
return dtTable;
}
}

You can try
DataTable.Rows[i].Cells[j].InnerText;
Where DataTable is the id of your table, i is the row and j is the cells.

Related

GridView (Aspx)(CSV) Data is not displayed correctly in the rows

The data is not displayed correctly in the columns.
The CSV consists of 7 columns. Rows are of different length.
I can not upload a picture.(https://ibb.co/0fnfLW7)
DataTable tblcsv = new DataTable();
tblcsv.Columns.Add("Vorname");
tblcsv.Columns.Add("Nachname");
tblcsv.Columns.Add("RFID");
string csvData = File.ReadAllText(csvPath);
//spliting row after new line
foreach (string csvRow in csvData.Split(';'))
{
if (!string.IsNullOrEmpty(csvRow))
{
//Adding each row into datatable
tblcsv.Rows.Add();
int count = 0;
foreach (string FileRec in csvRow.Split(';'))
{
tblcsv.Rows[tblcsv.Rows.Count - 1][count] = FileRec;
count++;
for(var x=0; x<7; x++)
{
//tblcsv[x][count] = FileRec;
}
count++;
}
}
//Calling Bind Grid Functions
BindgridStaffImport(tblcsv);
}
You split code is using ";", and should it not be "," if a csv?
The code will look much like this:
foreach (string csvRow in csvData.Split(';'))
{
if (!string.IsNullOrEmpty(csvRow))
{
//Adding each row into datatable
DataRow MyNewRow = tblcsv.NewRow();
int count = 0;
foreach (string FileRec in csvRow.Split(','))
{
MyNewRow[count] = FileRec;
count++;
}
tblcsv.Rows.Add(MyNewRow);
}
//Calling Bind Grid Functions
BindgridStaffImport(tblcsv);
So, use the "newRow" method to create a new blank row based on the table. Set the column values, and then add this new row to the rows collection of the table.
And even better is to use the TextFieldParser class.
So,
using Microsoft.VisualBasic.FileIO;
And then you can even assume say the first row has the colum names.
This:
We assume you read the csv file into stirng sFileLocal
// process csv file
TextFieldParser MyParse = new TextFieldParser(sFileLocal);
MyParse.TextFieldType = FieldType.Delimited;
MyParse.SetDelimiters(new string[] { "," });
MyParse.HasFieldsEnclosedInQuotes = true;
// add colums to table.
DataTable rstData = new DataTable();
foreach (string cCol in MyParse.ReadFields())
{
rstData.Columns.Add(cCol);
}
while (!MyParse.EndOfData)
{
string[] OneRow = MyParse.ReadFields();
rstData.Rows.Add(OneRow);
}
// Now display results in a grid
GridView1.DataSource = rstData;
GridView1.DataBind();
Quite much all above is you need.
Thank you very much for the support.
I now have a working variant.
However, the goal is to skip the first line, the header.
Are there any ideas how I can implement this.
List<string> headercolumns = new List<string> { "Vorname", "Nachname", };
DataTable dt = new DataTable();
foreach (string header in headercolumns)
{
dt.Columns.Add(header);
}
List<string> StaffList = new List<string>();
using (StreamReader filereader = new StreamReader(StaffFileUpload.FileContent))
{
string readline = string.Empty;
while ((readline = filereader.ReadLine()) != null)
{
StaffList.Add(readline);
}
if (StaffList != null && StaffList.Count > 0)
{
foreach (string info in StaffList)
{
DataRow row = dt.NewRow();
string[] mitarbeiter = info.Split(';');
for (int i = 0; i < mitarbeiter.Length; i++)
{
row[i] = mitarbeiter[i];
}
dt.Rows.Add(row);
}
}
}

how can i convert xml document to data table in c#

i am getting the following response from api as xml
<ROOT>
<valid>1</valid>
<org_name> test org </org_name>
<count_of_vedios>3</count_of_vedios>
<total_length>351</total_length>
<Video1>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video1>
<Video2>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video2>
<Video3>
<Title>Chalte Chalte</Title>
<Director>Aziz Mirza</Director>
<Length>145 Mins</Length>
<Format>DVD</Format>
<Rating>N/R</Rating>
</Video3>
</ROOT>
i need to fill some fields of aspx page with the information :
org_name : test org
count_of_vedios : 3
total_length : 351
also i need to fill gridview with the vedios that is in nodes
Title | Director | Length | Format | Rating |
dataset will have 4 tables here , so what i did is replace the vedio# tage with vedio , now the dataset will have 2 tables one for the general nodes and the another for vedios
DataTable general_dt = new DataTable();
DataTable vedios_dt = new DataTable();
string xml_str = document.DocumentElement.InnerXml.ToString();
xml_str = Regex.Replace(xml_str, #"<Video[0-9]{1,3}>", "<Video>");
xml_str = Regex.Replace(xml_str, #"<\/Video[0-9]{1,3}>", "</Video>");
DataSet ds = new DataSet();
ds.ReadXml(new System.IO.StringReader(xml_str));
if (ds.Tables.Count > 0)
{
XmlNode newnode;
newnode = document.ReadNode(new XmlTextReader(new StringReader(xml_str)));
if (newnode["valid"].InnerText.ToString() == "1")
{
general_dt = ds.Tables[0];
vedios_dt = ds.Tables[1];
}
}````
Try xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Title", typeof(string));
dt.Columns.Add("Directory", typeof(string));
dt.Columns.Add("Length", typeof(string));
dt.Columns.Add("Format", typeof(string));
dt.Columns.Add("Rating", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
List<XElement> videos = doc.Root.Elements().Where(x => x.Name.LocalName.StartsWith("Video")).ToList();
foreach (XElement video in videos)
{
dt.Rows.Add(new object[] {
(string)video.Element("Title"),
(string)video.Element("Director"),
(string)video.Element("Length"),
(string)video.Element("Format"),
(string)video.Element("Rating")
});
}
}
}
}

Iterating through an Xml can't see the second Child node (C#)

I'm iterating parallel in 2 Xml docs. When an element value X from first Xml is
equal to the value in the second Xml (ex. USD== USD), it should write a
row in a DataTable with two columns. Element value X (USD) in the first Column
and an other child element value Y (value from ) from first Xml in the second col.
The second Xml has a single node with multiple elements.
DataTable dTable = new DataTable();
dTable.Columns.Add("ColumnOne");
dTable.Columns.Add("ColumnTwo");
DataRow dRow = null;
foreach (XmlNode nodeFirst in firstXmlDoc.SelectNodes("//ValCurs/Valute"))
{
foreach (XmlNode nodeSecond in secondXmlDoc.SelectSingleNode("SelectedVal"))
{
if (nodeFirst.SelectSingleNode("CharCode").InnerText == nodeSecond.InnerText)
{
dRow = dTable.NewRow();
dRow["ColumnOne"] = nodeFirst.SelectSingleNode("CharCode").InnerText;
dRow["ColumnTwo"] = nodeFirst.SelectSingleNode("Value").InnerText;
dTable.Rows.Add(dRow);
}
}
}
myDataGridView.DataSource = dTable;
This isn't working, I get in "nodeFirst.SelectSingleNode("Value").InnerText" a null value (" ") and it stops, filling the DataTable just with the "CharCode" value.
It's interesting that it worked the first few times I runned it, but it doesn't anymore.
First Xml:
<ValCurs>
<Valute ID="47">
<NumCode>978</NumCode>
<CharCode>EUR</CharCode>
<Nominal>1</Nominal>
<Name>Euro</Name>
<Value>20.3457</Value>
</Valute>
<Valute ID="44">
<NumCode>840</NumCode>
<CharCode>USD</CharCode>
<Nominal>1</Nominal>
<Name>Dolar S.U.A.</Name>
<Value>17.4603</Value>
</Valute>
...
</ValCurs>
Second Xml:
<SelectedVal>
<Cod>UAH</Cod>
<Cod>EUR</Cod>
<Cod>CAD</Cod>
<Cod>RON</Cod>
<Cod>NOK</Cod>
<Cod>RUB</Cod>
<Cod>JPY</Cod>
<Cod>AUD</Cod>
</SelectedVal>
Try following code using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string CURRENCY_FILE = #"c:\temp\test.xml";
const string COUNTRY_FILE = #"c:\temp\test1.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("NUMCODE", typeof(int));
dt.Columns.Add("CHARCODE", typeof(string));
dt.Columns.Add("Nominal", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(decimal));
XDocument currencyXml = XDocument.Load(CURRENCY_FILE);
List<XElement> valutes = currencyXml.Descendants("Valute").ToList();
foreach (XElement valute in valutes)
{
dt.Rows.Add(new object[] {
(int)valute.Attribute("ID"),
(int)valute.Element("NumCode"),
(string)valute.Element("CharCode"),
(int)valute.Element("Nominal"),
(string)valute.Element("Name"),
(decimal)valute.Element("Value")
});
}
XDocument countryXml = XDocument.Load(COUNTRY_FILE);
List<string> countries = countryXml.Descendants("Cod").Select(x => (string)x).ToList();
DataTable filteredTable = dt.AsEnumerable().Where(x => countries.Contains(x.Field<string>("CharCode"))).CopyToDataTable();
}
}
}

Reading/writing CSV/tab delimited files in c#

I need to read from a CSV/Tab delimited file and write to such a file as well from .net.
The difficulty is that I don't know the structure of each file and need to write the cvs/tab file to a datatable, which the FileHelpers library doesn't seem to support.
I've already written it for Excel using OLEDB, but can't really see a way to write a tab file for this, so will go back to a library.
Can anyone help with suggestions?
.NET comes with a CSV/tab delminited file parser called the TextFieldParser class.
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.aspx
It supports the full RFC for CSV files and really good error reporting.
I used this CsvReader, it is really great and well configurable. It behaves well with all kinds of escaping for strings and separators. The escaping in other quick and dirty implementations were poor, but this lib is really great at reading. With a few additional codelines you can also add a cache if you need to.
Writing is not supported but it rather trivial to implement yourself. Or inspire yourself from this code.
Simple example with CsvHelper
using (TextWriter writer = new StreamWriter(filePath)
{
var csvWriter = new CsvWriter(writer);
csvWriter.Configuration.Delimiter = "\t";
csvWriter.Configuration.Encoding = Encoding.UTF8;
csvWriter.WriteRecords(exportRecords);
}
Here are a couple CSV reader implementations:
http://www.codeproject.com/KB/database/CsvReader.aspx
http://www.heikniemi.fi/jhlib/ (just one part of the library; includes a CSV writer too)
I doubt there is a standard way to convert CSV to DataTable or database 'automatically', you'll have to write code to do that. How to do that is a separate question.
You'll create your datatable in code, and (presuming a header row) can create columns based on your first line in the file. After that, it will simply be a matter of reading the file and creating new rows based on the data therein.
You could use something like this:
DataTable Tbl = new DataTable();
using(StreamReader sr = new StreamReader(path))
{
int count = 0;
string headerRow = sr.Read();
string[] headers = headerRow.split("\t") //Or ","
foreach(string h in headers)
{
DataColumn dc = new DataColumn(h);
Tbl.Columns.Add(dc);
count++;
}
while(sr.Peek())
{
string data = sr.Read();
string[] cells = data.Split("\t")
DataRow row = new DataRow();
foreach(string c in cells)
{
row.Columns.Add(c);
}
Tbl.Rows.Add(row);
}
}
The above code has not been compiled, so it may have some errors, but it should get you on the right track.
You can read and write csv file..
This may be helpful for you.
pass split char to this parameter "serparationChar"
Example : -
private DataTable dataTable = null;
private bool IsHeader = true;
private string headerLine = string.Empty;
private List<string> AllLines = new List<string>();
private StringBuilder sb = new StringBuilder();
private char seprateChar = ',';
public DataTable ReadCSV(string path, bool IsReadHeader, char serparationChar)
{
seprateChar = serparationChar;
IsHeader = IsReadHeader;
using (StreamReader sr = new StreamReader(path,Encoding.Default))
{
while (!sr.EndOfStream)
{
AllLines.Add( sr.ReadLine());
}
createTemplate(AllLines);
}
return dataTable;
}
public void WriteCSV(string path,DataTable dtable,char serparationChar)
{
AllLines = new List<string>();
seprateChar = serparationChar;
List<string> StableHeadrs = new List<string>();
int colCount = 0;
using (StreamWriter sw = new StreamWriter(path))
{
foreach (DataColumn col in dtable.Columns)
{
sb.Append(col.ColumnName);
if(dataTable.Columns.Count-1 > colCount)
sb.Append(seprateChar);
colCount++;
}
AllLines.Add(sb.ToString());
for (int i = 0; i < dtable.Rows.Count; i++)
{
sb.Clear();
for (int j = 0; j < dtable.Columns.Count; j++)
{
sb.Append(Convert.ToString(dtable.Rows[i][j]));
if (dataTable.Columns.Count - 1 > j)
sb.Append(seprateChar);
}
AllLines.Add(sb.ToString());
}
foreach (string dataline in AllLines)
{
sw.WriteLine(dataline);
}
}
}
private DataTable createTemplate(List<string> lines)
{
List<string> headers = new List<string>();
dataTable = new DataTable();
if (lines.Count > 0)
{
string[] argHeaders = null;
for (int i = 0; i < lines.Count; i++)
{
if (i > 0)
{
DataRow newRow = dataTable.NewRow();
// others add to rows
string[] argLines = lines[i].Split(seprateChar);
for (int b = 0; b < argLines.Length; b++)
{
newRow[b] = argLines[b];
}
dataTable.Rows.Add(newRow);
}
else
{
// header add to columns
argHeaders = lines[0].Split(seprateChar);
foreach (string c in argHeaders)
{
DataColumn column = new DataColumn(c, typeof(string));
dataTable.Columns.Add(column);
}
}
}
}
return dataTable;
}
I have found best solution
http://www.codeproject.com/Articles/415732/Reading-and-Writing-CSV-Files-in-Csharp
Just I had to re-write
void ReadTest()
{
// Read sample data from CSV file
using (CsvFileReader reader = new CsvFileReader("ReadTest.csv"))
{
CsvRow row = new CsvRow();
while (reader.ReadRow(row))
{
foreach (string s in row)
{
Console.Write(s);
Console.Write(" ");
}
Console.WriteLine();
row = new CsvRow(); //this line added
}
}
}
Well, there is another library Cinchoo ETL - an open source one, for reading and writing CSV files.
Couple of ways you can read CSV files
Id, Name
1, Tom
2, Mark
This is how you can use this library to read it
using (var reader = new ChoCSVReader("emp.csv").WithFirstLineHeader())
{
foreach (dynamic item in reader)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.Name);
}
}
If you have POCO object defined to match up with CSV file like below
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
You can parse the same file using this POCO class as below
using (var reader = new ChoCSVReader<Employee>("emp.csv").WithFirstLineHeader())
{
foreach (var item in reader)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.Name);
}
}
Please check out articles at CodeProject on how to use it.
Disclaimer: I'm the author of this library

Exporting the values in List to excel

Hi I am having a list container which contains the list of values. I wish to export the list values directly to Excel. Is there any way to do it directly?
OK, here is a step-by-step guide if you want to use COM.
You have to have Excel installed.
Add a reference to your project to the excel interop dll. To do this
on the .NET tab select
Microsoft.Office.Interop.Excel.
There could be multiple assemblies
with this name. Select the
appropriate for your Visual Studio
AND Excel version.
Here is a code sample to create a new Workbook and fill a column with
the items from your list.
using NsExcel = Microsoft.Office.Interop.Excel;
public void ListToExcel(List<string> list)
{
//start excel
NsExcel.ApplicationClass excapp = new Microsoft.Office.Interop.Excel.ApplicationClass();
//if you want to make excel visible
excapp.Visible = true;
//create a blank workbook
var workbook = excapp.Workbooks.Add(NsExcel.XlWBATemplate.xlWBATWorksheet);
//or open one - this is no pleasant, but yue're probably interested in the first parameter
string workbookPath = "C:\test.xls";
var workbook = excapp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
//Not done yet. You have to work on a specific sheet - note the cast
//You may not have any sheets at all. Then you have to add one with NsExcel.Worksheet.Add()
var sheet = (NsExcel.Worksheet)workbook.Sheets[1]; //indexing starts from 1
//do something usefull: you select now an individual cell
var range = sheet.get_Range("A1", "A1");
range.Value2 = "test"; //Value2 is not a typo
//now the list
string cellName;
int counter = 1;
foreach (var item in list)
{
cellName = "A" + counter.ToString();
var range = sheet.get_Range(cellName, cellName);
range.Value2 = item.ToString();
++counter;
}
//you've probably got the point by now, so a detailed explanation about workbook.SaveAs and workbook.Close is not necessary
//important: if you did not make excel visible terminating your application will terminate excel as well - I tested it
//but if you did it - to be honest - I don't know how to close the main excel window - maybee somewhere around excapp.Windows or excapp.ActiveWindow
}
Using ClosedXML edit library( there is no need to install MS Excel
I just write a simple example to show you how you can name the file, the worksheet and select cells:
var workbook = new XLWorkbook();
workbook.AddWorksheet("sheetName");
var ws = workbook.Worksheet("sheetName");
int row = 1;
foreach (object item in itemList)
{
ws.Cell("A" + row.ToString()).Value = item.ToString();
row++;
}
workbook.SaveAs("yourExcel.xlsx");
If you prefer you can create a System.Data.DataSet or a System.Data.DataTable with all data and then just add it as a workseet with workbook.AddWorksheet(yourDataset) or workbook.AddWorksheet(yourDataTable);
Using the CSV idea, if it's just a list of Strings. Assuming l is your list:
using System.IO;
using(StreamWriter sw = File.CreateText("list.csv"))
{
for(int i = 0; i < l.Count; i++)
{
sw.WriteLine(l[i]);
}
}
Fast way - ArrayToExcel (github)
byte[] excel = myList.ToExcel();
File.WriteAllBytes("result.xlsx", excel);
The simplest way using ClosedXml.
Imports ClosedXML.Excel
var dataList = new List<string>() { "a", "b", "c" };
var workbook = new XLWorkbook(); //creates the workbook
var wsDetailedData = workbook.AddWorksheet("data"); //creates the worksheet with sheetname 'data'
wsDetailedData.Cell(1, 1).InsertTable(dataList); //inserts the data to cell A1 including default column name
workbook.SaveAs(#"C:\data.xlsx"); //saves the workbook
For more info, you can also check wiki of ClosedXml.
https://github.com/closedxml/closedxml/wiki
Exporting values List to Excel
Install in nuget next reference
Install-Package Syncfusion.XlsIO.Net.Core -Version 17.2.0.35
Install-Package ClosedXML -Version 0.94.2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ClosedXML;
using ClosedXML.Excel;
using Syncfusion.XlsIO;
namespace ExporteExcel
{
class Program
{
public class Auto
{
public string Marca { get; set; }
public string Modelo { get; set; }
public int Ano { get; set; }
public string Color { get; set; }
public int Peronsas { get; set; }
public int Cilindros { get; set; }
}
static void Main(string[] args)
{
//Lista Estatica
List<Auto> Auto = new List<Program.Auto>()
{
new Auto{Marca = "Chevrolet", Modelo = "Sport", Ano = 2019, Color= "Azul", Cilindros=6, Peronsas= 4 },
new Auto{Marca = "Chevrolet", Modelo = "Sport", Ano = 2018, Color= "Azul", Cilindros=6, Peronsas= 4 },
new Auto{Marca = "Chevrolet", Modelo = "Sport", Ano = 2017, Color= "Azul", Cilindros=6, Peronsas= 4 }
};
//Inizializar Librerias
var workbook = new XLWorkbook();
workbook.AddWorksheet("sheetName");
var ws = workbook.Worksheet("sheetName");
//Recorrer el objecto
int row = 1;
foreach (var c in Auto)
{
//Escribrie en Excel en cada celda
ws.Cell("A" + row.ToString()).Value = c.Marca;
ws.Cell("B" + row.ToString()).Value = c.Modelo;
ws.Cell("C" + row.ToString()).Value = c.Ano;
ws.Cell("D" + row.ToString()).Value = c.Color;
ws.Cell("E" + row.ToString()).Value = c.Cilindros;
ws.Cell("F" + row.ToString()).Value = c.Peronsas;
row++;
}
//Guardar Excel
//Ruta = Nombre_Proyecto\bin\Debug
workbook.SaveAs("Coches.xlsx");
}
}
}
You could output them to a .csv file and open the file in excel. Is that direct enough?
The most straightforward way (in my opinion) would be to simply put together a CSV file. If you want to get into formatting and actually writing to a *.xlsx file, there are more complicated solutions (and APIs) to do that for you.
the one easy way to do it is to open Excel create sheet containing test data you want to export then say to excel save as xml open the xml see the xml format excel is expecting and generate it by head replacing the test data with export data
SpreadsheetML Markup Spec
#lan this is xml fo a simle execel file with one column value i genereted with office 2003 this format is for office 2003 and above
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<Author>Dancho</Author>
<LastAuthor>Dancho</LastAuthor>
<Created>2010-02-05T10:15:54Z</Created>
<Company>cc</Company>
<Version>11.9999</Version>
</DocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>13800</WindowHeight>
<WindowWidth>24795</WindowWidth>
<WindowTopX>480</WindowTopX>
<WindowTopY>105</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="6" x:FullColumns="1"
x:FullRows="1">
<Row>
<Cell><Data ss:Type="String">Value1</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Value2</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Value3</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Value4</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Value5</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Value6</Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<Selected/>
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>5</ActiveRow>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet2">
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet3">
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>
Depending on the environment you're wanting to do this in, it is possible by using the Excel Interop. It's quite a mess dealing with COM however and ensuring you clear up resources else Excel instances stay hanging around on your machine.
Checkout this MSDN Example if you want to learn more.
Depending on your format you could produce CSV or SpreadsheetML yourself, thats not too hard. Other alternatives are to use 3rd party libraries to do it. Obviously they cost money though.
List<"classname"> getreport = cs.getcompletionreport();
var getreported = getreport.Select(c => new { demographic = c.rName);
where cs.getcompletionreport() reference class file is Business Layer for App
I hope this helps.
I know, I am late to this party, however I think it could be helpful for others.
Already posted answers are for csv and other one is by Interop dll where you need to install excel over the server, every approach has its own pros and cons.
Here is an option which will give you
Perfect excel output [not csv]
With perfect excel and your data type match
Without excel installation
Pass list and get Excel output :)
you can achieve this by using NPOI DLL, available for both .net as well as for .net core
Steps :
Import NPOI DLL
Add Section 1 and 2 code provided below
Good to go
Section 1
This code performs below task :
Creating New Excel object - _workbook = new XSSFWorkbook();
Creating New Excel Sheet object - _sheet =_workbook.CreateSheet(_sheetName);
Invokes WriteData() - explained later Finally, creating and
returning MemoryStream object
=============================================================================
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
namespace GenericExcelExport.ExcelExport
{
public interface IAbstractDataExport
{
HttpResponseMessage Export(List exportData, string fileName, string sheetName);
}
public abstract class AbstractDataExport : IAbstractDataExport
{
protected string _sheetName;
protected string _fileName;
protected List _headers;
protected List _type;
protected IWorkbook _workbook;
protected ISheet _sheet;
private const string DefaultSheetName = "Sheet1";
public HttpResponseMessage Export
(List exportData, string fileName, string sheetName = DefaultSheetName)
{
_fileName = fileName;
_sheetName = sheetName;
_workbook = new XSSFWorkbook(); //Creating New Excel object
_sheet = _workbook.CreateSheet(_sheetName); //Creating New Excel Sheet object
var headerStyle = _workbook.CreateCellStyle(); //Formatting
var headerFont = _workbook.CreateFont();
headerFont.IsBold = true;
headerStyle.SetFont(headerFont);
WriteData(exportData); //your list object to NPOI excel conversion happens here
//Header
var header = _sheet.CreateRow(0);
for (var i = 0; i < _headers.Count; i++)
{
var cell = header.CreateCell(i);
cell.SetCellValue(_headers[i]);
cell.CellStyle = headerStyle;
}
for (var i = 0; i < _headers.Count; i++)
{
_sheet.AutoSizeColumn(i);
}
using (var memoryStream = new MemoryStream()) //creating memoryStream
{
_workbook.Write(memoryStream);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memoryStream.ToArray())
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue
("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = $"{_fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
};
return response;
}
}
//Generic Definition to handle all types of List
public abstract void WriteData(List exportData);
}
}
=============================================================================
Section 2
In section 2, we will be performing below steps :
Converts List to DataTable Reflection to read property name, your
Column header will be coming from here
Loop through DataTable to Create excel Rows
=============================================================================
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text.RegularExpressions;
namespace GenericExcelExport.ExcelExport
{
public class AbstractDataExportBridge : AbstractDataExport
{
public AbstractDataExportBridge()
{
_headers = new List<string>();
_type = new List<string>();
}
public override void WriteData<T>(List<T> exportData)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
{
var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
_type.Add(type.Name);
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ??
prop.PropertyType);
string name = Regex.Replace(prop.Name, "([A-Z])", " $1").Trim(); //space separated
//name by caps for header
_headers.Add(name);
}
foreach (T item in exportData)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
IRow sheetRow = null;
for (int i = 0; i < table.Rows.Count; i++)
{
sheetRow = _sheet.CreateRow(i + 1);
for (int j = 0; j < table.Columns.Count; j++)
{
ICell Row1 = sheetRow.CreateCell(j);
string type = _type[j].ToLower();
var currentCellValue = table.Rows[i][j];
if (currentCellValue != null &&
!string.IsNullOrEmpty(Convert.ToString(currentCellValue)))
{
if (type == "string")
{
Row1.SetCellValue(Convert.ToString(currentCellValue));
}
else if (type == "int32")
{
Row1.SetCellValue(Convert.ToInt32(currentCellValue));
}
else if (type == "double")
{
Row1.SetCellValue(Convert.ToDouble(currentCellValue));
}
}
else
{
Row1.SetCellValue(string.Empty);
}
}
}
}
}
}
=============================================================================
Now you just need to call
WriteData() function by passing your list, and it will provide you your excel.
I have tested it in WEB API and WEB API Core, works like a charm.
Pass List to "Write" Method, which will convert the list to buffer and return buffer, a file will be downloaded
byte[] buffer = Write(ListData, true, "AttendenceSummary"); return File(buffer, "application/excel", reportTitle + ".xlsx");
public static byte[] Write<T>(IEnumerable<T> list, bool xlsxExtension, string sheetName = "ExportData")
{
if (list == null)
{
throw new ArgumentNullException("list");
}
XSSFWorkbook hssfworkbook = new XSSFWorkbook();
int Rowspersheet = 15000;
int TotalRows = list.Count();
int TotalSheets = TotalRows / Rowspersheet;
for (int i = 0; i <= TotalSheets; i++)
{
ISheet sheet1 = hssfworkbook.CreateSheet(sheetName + "_" + i);
IRow row = sheet1.CreateRow(0);
int index = 0;
foreach (PropertyInfo property in typeof(T).GetProperties())
{
ICellStyle cellStyle = hssfworkbook.CreateCellStyle();
IFont cellFont = hssfworkbook.CreateFont();
cellFont.Boldweight = (short)NPOI.SS.UserModel.FontBoldWeight.Bold;
cellStyle.SetFont(cellFont);
ICell cell = row.CreateCell(index++);
cell.CellStyle = cellStyle;
cell.SetCellValue(property.Name);
}
int rowIndex = 1;
// int rowIndex2 = 1;
foreach (T obj in list.Skip(Rowspersheet * i).Take(Rowspersheet))
{
row = sheet1.CreateRow(rowIndex++);
index = 0;
foreach (PropertyInfo property in typeof(T).GetProperties())
{
ICell cell = row.CreateCell(index++);
cell.SetCellValue(Convert.ToString(property.GetValue(obj)));
}
}
}
MemoryStream file = new MemoryStream();
hssfworkbook.Write(file);
return file.ToArray();
}

Categories