Generating a HTML table from an Excel file using EPPlus? - excel

I would like to generate a HTML table from an excel file. The EPPlus package provides a .net API for manipulating excel file. I would be happy to know whether it is possible to generate a HTML table code from an Excel file using EPPlus? I couldn't find anything on the documentation, but intuition tells me that there should be a way to do it
Thank you!

If you are looking for something built into EPPlus, I havent seen anything that will export directly HTML.
Best thing would be to bring in the Excel file to EPPlus and extract the data to a collection or DataTable. That should be pretty straight forward.
From there, there is plenty of documentation on how to get that to an html table. Quick search turned up this as the first hit:
Datatable to html Table

I wrote some code, you can try this.
static void Main(string[] args)
{
ExcelPackage p = new ExcelPackage(new System.IO.FileInfo("X.XLSX"));
var sheet = p.Workbook.Worksheets["HMTD"];
var noOfCol = sheet.Dimension.End.Column;
var noOfRow = sheet.Dimension.End.Row;
StringBuilder s = new StringBuilder();
s.Append("<table>");
for (int i = 1; i < noOfRow; i++)
{
s.Append("<tr>");
for (int j = 1; j < noOfCol; j++)
{
int colspan = 1;
int rowspan = 1;
if (!sheet.Cells[i, j].Merge || (sheet.Cells[i, j].Merge && isFirstMergeRange(sheet, sheet.Cells[i, j].Address, ref colspan, ref rowspan)))
{
s.Append("<td rowspan='" + rowspan + "' colspan='" + colspan + "'>");
if(sheet.Cells[i,j] != null && sheet.Cells[i,j].Value != null)
s.Append(sheet.Cells[i,j].Value.ToString());
s.Append("</td>");
}
}
s.Append("</tr>");
}
s.Append("</table>");
System.IO.File.WriteAllText("duc.html",s.ToString());
Console.ReadKey();
}
private static bool isFirstMergeRange(ExcelWorksheet sheet, string address, ref int colspan, ref int rowspan)
{
colspan = 1;
rowspan = 1;
foreach (var item in sheet.MergedCells)
{
var s = item.Split(':');
if (s.Length > 0 && s[0].Equals(address)){
ExcelRange range = sheet.Cells[item];
colspan = range.End.Column - range.Start.Column;
rowspan = range.End.Row - range.Start.Row;
if(colspan == 0) colspan = 1;
if(rowspan == 0) rowspan = 1;
return true;
}
}
return false;
}

Based on the answer from Duc Tran Minh, it works fine for me after I modified the code like this:
static void Main(string[] args)
{
ExcelPackage p = new ExcelPackage(new System.IO.FileInfo("X.XLSX"));
var sheet = p.Workbook.Worksheets["HMTD"];
var noOfCol = sheet.Dimension.End.Column;
var noOfRow = sheet.Dimension.End.Row;
StringBuilder s = new StringBuilder();
s.Append("<table>");
for (int i = 1; i <= noOfRow; i++)
{
s.Append("<tr>");
for (int j = 1; j <= noOfCol; j++)
{
int colspan = 1;
int rowspan = 1;
if (!sheet.Cells[i, j].Merge || (sheet.Cells[i, j].Merge && isFirstMergeRange(sheet, sheet.Cells[i, j].Address, ref colspan, ref rowspan)))
{
s.Append("<td rowspan='" + rowspan + "' colspan='" + colspan + "'>");
if(sheet.Cells[i,j] != null && sheet.Cells[i,j].Value != null)
s.Append(sheet.Cells[i,j].Value.ToString());
s.Append("</td>");
}
}
s.Append("</tr>");
}
s.Append("</table>");
System.IO.File.WriteAllText("duc.html",s.ToString());
Console.ReadKey();
}
bool isFirstMergeRange(ExcelWorksheet sheet, string address, ref int colspan, ref int rowspan)
{
colspan = 1;
rowspan = 1;
foreach (var item in sheet.MergedCells)
{
var s = item.Split(':');
if (s.Length > 0 && s[0].Equals(address))
{
ExcelRange range = sheet.Cells[item];
colspan = range.End.Column - range.Start.Column + 1;
rowspan = range.End.Row - range.Start.Row + 1;
return true;
}
}
return false;
}

Related

How to get schedule element data in revit using C#

I am new to Revit API and am working in C#. I want to get the schedule element parameters value using C#. I used the below code to get the view schedule.
var viewSchedule = new FilteredElementCollector(document)
.OfClass(typeof(ViewSchedule))
.FirstOrDefault(e => e.Name == "MyScheduleName") as ViewSchedule;
Schedule Element Data
From the above schedule, I used the below code to get the element data (please refer the above screenshot link) but it taking long time to reflect the output (10 to 15 seconds).
var rowCount = viewSchedule.GetTableData().GetSectionData(SectionType.Body).NumberOfRows;
var colCount = viewSchedule.GetTableData().GetSectionData(SectionType.Body).NumberOfColumns;
for (int i = 0; i < rowCount; i++)
{
for (int j = 0; j < colCount; j++)
{
data += viewSchedule.GetCellText(SectionType.Body, i, j);
}
}
Please let me know is there any alternate approach to get the schedule data using C#.
Thanks in advance.
Maybe you can also use ViewSchedule.Export as demonstrated by The Building Coder discussing The Schedule API and Access to Schedule Data.
Yes, you can easily access Schedule data without exporting.
Firstly, get all the schedules and read the data cell by cell. Secondly, create dictionary and store data in form of key, value pairs. Now you can use the schedule data as you want. I have tried this in Revit 2019.
Here is the implementation.
public void getScheduleData(Document doc)
{
FilteredElementCollector collector = new FilteredElementCollector(doc);
IList<Element> collection = collector.OfClass(typeof(ViewSchedule)).ToElements();
String prompt = "ScheduleData :";
prompt += Environment.NewLine;
foreach (Element e in collection)
{
ViewSchedule viewSchedule = e as ViewSchedule;
TableData table = viewSchedule.GetTableData();
TableSectionData section = table.GetSectionData(SectionType.Body);
int nRows = section.NumberOfRows;
int nColumns = section.NumberOfColumns;
if (nRows > 1)
{
//valueData.Add(viewSchedule.Name);
List<List<string>> scheduleData = new List<List<string>>();
for (int i = 0; i < nRows; i++)
{
List<string> rowData = new List<string>();
for (int j = 0; j < nColumns; j++)
{
rowData.Add(viewSchedule.GetCellText(SectionType.Body, i, j));
}
scheduleData.Add(rowData);
}
List<string> columnData = scheduleData[0];
scheduleData.RemoveAt(0);
DataMapping(columnData, scheduleData);
}
}
}
public static void DataMapping(List<string> keyData, List<List<string>>valueData)
{
List<Dictionary<string, string>> items= new List<Dictionary<string, string>>();
string prompt = "Key/Value";
prompt += Environment.NewLine;
foreach (List<string> list in valueData)
{
for (int key=0, value =0 ; key< keyData.Count && value< list.Count; key++,value++)
{
Dictionary<string, string> newItem = new Dictionary<string, string>();
string k = keyData[key];
string v = list[value];
newItem.Add(k, v);
items.Add(newItem);
}
}
foreach (Dictionary<string, string> item in items)
{
foreach (KeyValuePair<string, string> kvp in item)
{
prompt += "Key: " + kvp.Key + ",Value: " + kvp.Value;
prompt += Environment.NewLine;
}
}
Autodesk.Revit.UI.TaskDialog.Show("Revit", prompt);
}

MVC Linq throws intermittent null reference exception during export to Excel

I'm using the same code in 6 Areas, each a separate database. Been working fine for a long time, now fails in 3 of the 6 with a null reference exception. Classes all the same, all database tables hold data. First method is the view which displays the data, second called by a link in the view to export the data to Excel. 3 cases display and export correctly. In 2 out of the other 3 cases the data is displayed correctly in the view, and the null exception is thrown at the point the data should be being retrieved in the export method. In the last case the null exception is thrown when trying to return the view. Simply can't understand how it works in some instances but not in others.
public ActionResult PVS(string studySite, string currentFilter, int? page)
{
ViewBag.SelectedID = studySite;
if (studySite != null)
page = 1;
else
studySite = currentFilter;
ViewBag.CurrentFilter = studySite;
IQueryable<PVS> schedule = db.PVS.OrderBy(v => v.SiteNumber).ThenBy(v => v.Participant);
if (studySite != null)
{
string selectedID = studySite;
images = schedule.Where(v => v.SiteNumber == selectedID);
}
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(schedule.ToPagedList(pageNumber, pageSize));
}
public void ExportPVSToExcel()
{
var grid = new System.Web.UI.WebControls.GridView();
var pvs = db.PVS.OrderBy(p => p.SiteNumber).ThenBy(p => p.Participant).ToList();
grid.DataSource = pvs;
grid.DataBind();
// create an Excel worksheet for the data export
ExcelPackage excel = new ExcelPackage();
var workSheet = excel.Workbook.Worksheets.Add("PVS");
var totalCols = grid.Rows[0].Cells.Count;
var totalRows = grid.Rows.Count;
var headerRow = grid.HeaderRow;
for (var i = 1; i <= totalCols; i++)
{
workSheet.Cells[1, i].Value = headerRow.Cells[i - 1].Text;
}
for (var j = 1; j <= totalRows; j++)
{
for (var i = 1; i <= totalCols; i++)
{
var data = pvs.ElementAt(j - 1);
workSheet.Cells[j + 1, i].Value = data.GetType().GetProperty(headerRow.Cells[i - 1].Text).GetValue(data, null);
}
}
using (var memoryStream = new MemoryStream())
{
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=PVS.xlsx");
excel.SaveAs(memoryStream);
memoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}

MVC 5 Epplus Excel Found Unreadable Content

I am trying to write some information to an excel file. I can write data in it with using EPPlus. And download the excel file. But when I run and download this file and open, I see this error.
"Excel found unreadable content in filename.xls. Do you want to recover the contents of this workbook? If you trust the source of this workbook, click Yes."
Even if I did not write anything to file, I got this error.
My code in Excel class is:
using MaasRaporlari.Models;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
namespace MaasRaporlari.Controllers
{
class AyrintiliHarcamaRapor
{
public List<AyrintiliHarcamaProgramiVM2> Ayrintili;
private static int RaporaEklenebilecekIcerikSayısı = 33;
public string ExcelTemplatePath { get; set; } // = HostingEnvironment.MapPath(Url.Content("~/Content/Xsl/")); //#"C:\test\OdemeEmriBelgesi.xlsx";
public string ExcelResultPath { get; set; } // = #"C:\test\OdemeEmriSonuc.xlsx";
public FileStream Save()
{
try
{
ExcelTemplatePath = HttpContext.Current.Server.MapPath("~/Images/AyrintiliHarcamaProgrami.xlsx");
ExcelResultPath = HttpContext.Current.Server.MapPath("~/Images/Harcama.xls");
var File = new FileInfo(ExcelTemplatePath);
using (ExcelPackage package = new ExcelPackage(File))
{
package.Load(new FileStream(ExcelTemplatePath, FileMode.Open));
int sheetCount = (int)Math.Ceiling((double)Ayrintili.Count / RaporaEklenebilecekIcerikSayısı);
ExcelWorksheet workSheet = package.Workbook.Worksheets["Sheet1"];
List<ExcelWorksheet> workSheets = new List<ExcelWorksheet>();
workSheets.Add(workSheet);
package.Stream.Position = 0;
if (sheetCount >= 2)
{
for (int i = 0; i < sheetCount - 1; i++)
{
ExcelWorksheet tempSheet = package.Workbook.Worksheets.Add(string.Format("Sheet{0}", i + 2), workSheet);
workSheets.Add(tempSheet);
}
}
int icerikSayac = 0;
foreach (ExcelWorksheet workSheetItem in workSheets)
{
package.Stream.Position = 0;
decimal MiktarToplam1 = 0;
decimal MiktarToplam2 = 0;
decimal MiktarToplam3 = 0;
decimal MiktarToplam4 = 0;
decimal MiktarToplam5 = 0;
decimal OranToplam1 = 0;
decimal OranToplam2 = 0;
decimal OranToplam3 = 0;
decimal OranToplam4 = 0;
decimal OranToplam5 = 0;
MiktarToplam Toplam = new MiktarToplam();
int rowPointer = 10;
for (int i = 0; i < RaporaEklenebilecekIcerikSayısı; i++)
{
if (icerikSayac < Ayrintili.Count)
{
var item = Ayrintili[icerikSayac];
package.Stream.Position = 0;
MiktarToplam5 = item.Miktar1 + item.Miktar2 + item.Miktar3 + item.Miktar4;
OranToplam5 = item.Oran1 + item.Oran2 + item.Oran3 + item.Oran4;
MiktarToplam1 += item.Miktar1;
MiktarToplam2 += item.Miktar2;
MiktarToplam3 += item.Miktar3;
MiktarToplam4 += item.Miktar4;
OranToplam1 += item.Oran1;
OranToplam2 += item.Oran2;
OranToplam3 += item.Oran3;
OranToplam4 += item.Oran4;
workSheetItem.Cells["A" + rowPointer.ToString()].Value = item.One;
workSheetItem.Cells["B" + rowPointer.ToString()].Value = item.Two;
workSheetItem.Cells["C" + rowPointer.ToString()].Value = item.Aciklama;
workSheetItem.Cells["D" + rowPointer.ToString()].Value = item.Miktar1;
workSheetItem.Cells["F" + rowPointer.ToString()].Value = item.Miktar2;
workSheetItem.Cells["H" + rowPointer.ToString()].Value = item.Miktar3;
workSheetItem.Cells["J" + rowPointer.ToString()].Value = item.Miktar4;
workSheetItem.Cells["E" + rowPointer.ToString()].Value = item.Oran1;
workSheetItem.Cells["G" + rowPointer.ToString()].Value = item.Oran2;
workSheetItem.Cells["I" + rowPointer.ToString()].Value = item.Oran3;
workSheetItem.Cells["K" + rowPointer.ToString()].Value = item.Oran4;
workSheetItem.Cells["AC" + rowPointer.ToString()].Value = MiktarToplam5;
workSheetItem.Cells["AD" + rowPointer.ToString()].Value = OranToplam5;
rowPointer++;
icerikSayac++;
}
}
workSheetItem.Cells["D33"].Value = MiktarToplam1;
workSheetItem.Cells["E33"].Value = OranToplam1;
workSheetItem.Cells["F33"].Value = MiktarToplam2;
workSheetItem.Cells["G33"].Value = OranToplam2;
workSheetItem.Cells["H33"].Value = MiktarToplam3;
workSheetItem.Cells["I33"].Value = OranToplam3;
workSheetItem.Cells["J33"].Value = MiktarToplam4;
workSheetItem.Cells["K33"].Value = OranToplam4;
}
using (FileStream outStream = new FileStream(ExcelResultPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
package.Stream.Position = 0;
package.SaveAs(outStream);
outStream.Position = 0;
package.Stream.Dispose();
return (outStream);
}
}
}
catch (Exception)
{
throw;
}
}
public class MiktarToplam
{
public decimal Toplam { get; set; }
public MiktarToplam()
{
Toplam = 0;
}
}
}
}
Just a few quick questions:
Is it necessary to put the file in the ExcelPackage constructor and then load it(package.Load)?
Why do you set package.Stream.Postision = 0 on line 34 and again line 69?
I am doing this in my solution(wb is the workbook):
var ms = new MemoryStream();
wb.SaveAs(ms);
ms.Seek(0, SeekOrigin.Begin);
Have you tried saving to file instead (Just to make sure that everything is working).
Epplus is an old tool for Excel. If you look a little, you can see lots of better tools. And you should research carefully. Additionally, you should look to these tool's websites. When was the last commit or update?
NPOI and GemBox one of the best tools. Good luck.

Handle Null Value In Gridview During Exporting To Excel

I am working with a C# Windows application. Trying to export data from gridview to Excel , but when the gridview column is empty I do get error message.
How to handle that? Please help
This is my code
// Store Header from Gridview to Excel
for (int i = 1; i < dgvresult.Columns.Count + 1; i++)
{
Excel.Cells[1, i] = dgvresult.Columns[i - 1].HeaderText;
}
// Loop rows and columns of Gridview to store to Excel
for (int i = 0; i < dgvresult.Rows.Count; i++)
{
for (int j = 0; j < dgvresult.Columns.Count; j++)
{
Excel.Cells[i + 2, j + 1] = dgvresult.Rows[i].Cells[j].Value.ToString(); // Here when the value in Gridview is empty error how to handle this
}
}
Excel.ActiveWorkbook.SaveCopyAs("D:\\Asserts.xls");
Excel.ActiveWorkbook.Saved = true;
Excel.Quit();
MessageBox.Show("Excel file created,you can find the file D:\\Asserts.xls");
Excel.Visible = true;
Found solution do a checking by code below
private void btnexport_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.ApplicationClass Excel = new Microsoft.Office.Interop.Excel.ApplicationClass();
Excel.Application.Workbooks.Add(Type.Missing);
Excel.Columns.ColumnWidth = 14;
// Store Header from Gridview to Excel
for (int i = 1; i < dgvresult.Columns.Count + 1; i++)
{
Excel.Cells[1, i] = dgvresult.Columns[i - 1].HeaderText;
}
// Loop rows and columns of Gridview to store to Excel
for (int i = 0; i < dgvresult.Rows.Count; i++)
{
for (int j = 0; j < dgvresult.Columns.Count; j++)
{
if (dgvresult.Rows[i].Cells[j].Value == null)
{
dgvresult.Rows[i].Cells[j].Value = "NA"; // Where the gridview is empty do a checking and Insert NA
}
Excel.Cells[i + 2, j + 1] = dgvresult.Rows[i].Cells[j].Value.ToString();
}
}
Excel.ActiveWorkbook.SaveCopyAs("D:\\Asserts.xls");
Excel.ActiveWorkbook.Saved = true;
Excel.Quit();
MessageBox.Show("Excel file created,you can find the file D:\\Asserts.xls");
Excel.Visible = true;
}

The method 'Equals' is not supported

public List<Health_Scheme_System.Employee> GetPenEmployeeTable()
{
Health_Scheme_System.Health_Scheme_SystemDB db = new Health_Scheme_System.Health_Scheme_SystemDB();
var x = (from c in db.Employees
where c.Pensioners.Equals (1)
select c);
return x.ToList();
}
//Selecting multiple columns from an HR view table together with the scheme name of scheme.
public List<EmployeesX> GetPensioners()
{
Health_Scheme_System.Health_Scheme_SystemDB db = new Health_Scheme_System.Health_Scheme_SystemDB();
List<Health_Scheme_System.EmployeeDirectory> listEmployeeView = GetPenEmployeeView();
List<Health_Scheme_System.Employee> listEmployeeTable = GetPenEmployeeTable();
List<Health_Scheme_System.Scheme> listSchemes = GetSchemes();
List<EmployeesX> listOfEmployees = new List<EmployeesX>();
//checking for comparision of getemployeeview to getemployee table and then to getschemes
//Then display the scheme name if they are similar.
for (int i = 0; i < listEmployeeView.Count; i++)
{
EmployeesX emp = new EmployeesX();
emp.ID_NO = listEmployeeView[i].ID_NO;
emp.FIRST_NAME = listEmployeeView[i].FIRST_NAME;
emp.LAST_NAME = listEmployeeView[i].LAST_NAME;
emp.LOCATION_CODE = listEmployeeView[i].LOCATION_CODE;
for (int j = 0; j < listEmployeeTable.Count; j++)
{
if (listEmployeeTable[j].EmployeeIDCard == listEmployeeView[i].ID_NO)
{
emp.Pensioners = listEmployeeTable[j].Pensioners;
for (int k = 0; k < listSchemes.Count; k++)
{
if (listEmployeeTable[j].SchemeID == listSchemes[k].SchemeID)
{
emp.SCHEME_NAME = listSchemes[k].Name;
emp.START_DATE = listEmployeeTable[j].StartSchemeDate;
}
}
}
}
listOfEmployees.Add(emp);
}
return listOfEmployees;
}
How can I make the same method with using .equals??
Have you tried this:
var x = (from c in db.Employees
where c.Pensioners == 1
select c)
Additional info:
If you use a method on an object in a linq query subsonic needs to know how to translate that into pur SQL code. That does not work by default and must be implemented for every known method on every supported type for every dataprovider (if differs from default implementation). So there is a bunch of work to do for subsonic.
A good starting point for knowning what's supported and what not is the TSqlFormatter class. Have a look at protected override Expression VisitMethodCall(MethodCallExpression m)
https://github.com/subsonic/SubSonic-3.0/blob/master/SubSonic.Core/Linq/Structure/TSqlFormatter.cs
There is already an implementation for Equals
else if (m.Method.Name == "Equals")
{
if (m.Method.IsStatic && m.Method.DeclaringType == typeof(object))
{
sb.Append("(");
this.Visit(m.Arguments[0]);
sb.Append(" = ");
this.Visit(m.Arguments[1]);
sb.Append(")");
return m;
}
else if (!m.Method.IsStatic && m.Arguments.Count == 1 && m.Arguments[0].Type == m.Object.Type)
{
sb.Append("(");
this.Visit(m.Object);
sb.Append(" = ");
this.Visit(m.Arguments[0]);
sb.Append(")");
return m;
}
else if (m.Method.IsStatic && m.Method.DeclaringType == typeof(string))
{
//Note: Not sure if this is best solution for fixing side issue with Issue #66
sb.Append("(");
this.Visit(m.Arguments[0]);
sb.Append(" = ");
this.Visit(m.Arguments[1]);
sb.Append(")");
return m;
}
}
I suppose Prnsioners is an integer type so you basically have to add another else if and recomplie subsonic.
This should work but I haven't tested it.
else if (!m.Method.IsStatic && m.Method.DeclaringType == typeof(int))
{
sb.Append("(");
this.Visit(m.Arguments[0]);
sb.Append(" = ");
this.Visit(m.Arguments[1]);
sb.Append(")");
return m;
}
(or you can try the == approach like in the example on the top).

Resources