Creating a dynamic number of workbooks using EPPlus - c#

I have what is essentially a database with tables owned by different groups within our larger group. I have developed an app that helps make Excel files we use to edit these tables that breaks out the tables by what group owns the table and creates an Excel workbook using EPPlus. The owners are defined in a csv file that I read in and assign to each table as I go through them. In each workbook it makes a tab for each tab that the group owns. So right now a simplified version of my code looks like:
using (ExcelPackage grp1 = new ExcelPackage())
{
using (ExcelPackage grp2 = new ExcelPackage())
{
using (ExcelPackage grp3 = new ExcelPackage())
{
// iterate thru list of tables and owners
foreach (string table in tablelist)
{
if (tableowner = group1)
{
ExcelWorksheet ws = grp1.Workbook.Worksheets.Add(currenttable.Name);
// do stuff
}
if (tableowner = group2)
{
ExcelWorksheet ws = grp2.Workbook.Worksheets.Add(currenttable.Name);
// do stuff
}
if (tableowner = group3)
{
ExcelWorksheet ws = grp3.Workbook.Worksheets.Add(currenttable.Name);
// do stuff
}
if (grp1.Workbook.Worksheets.Count > 0)
{
FileInfo grp1fi = new FileInfo(path);
grp1.SaveAs(grp1fi);
}
if (grp2.Workbook.Worksheets.Count > 0)
{
FileInfo grp2fi = new FileInfo(path);
grp2.SaveAs(grp2fi);
}
if (grp3.Workbook.Worksheets.Count > 0)
{
FileInfo grp3fi = new FileInfo(path);
grp3.SaveAs(grp3fi);
}
}
}
}
}
This works great as long as everything is only put into those 3 groups that I have the code in place for. But I'm running into the need to let the user define the groups to however many groups they need. So I need to be able to dynamically create the correct number of Excel files. Is this possible? I'm guessing if it is I'll have to find the number of unique groups in the csv file that I read in first. Then create the same number of lists in which to store the tables broken out by group. From there I could iterate through one of the lists and use a generic ExcelPackage that I dispose of after looping through all the tables for that group. Then move on to the second list, etc. I'm just not sure the best way to accomplish this.

You can do all of this in a simple for loop right? Or am I misunderstanding the question?
int NoOfWorkBooks = 5;
for (int i = 0; i < NoOfWorkBooks; i++)
{
using (ExcelPackage grp = new ExcelPackage())
{
if (tableowner == group)
{
ExcelWorksheet ws = grp.Workbook.Worksheets.Add(currenttable.Name);
FileInfo grp1fi = new FileInfo(string.Format(#"c:\temp\ExcelFile_{0}.xlsx", i));
grp.SaveAs(grp1fi);
}
}
}

Related

How to aggregate two worksheets to one workbook using openXML?

I want to aggregate two different worksheet from another workbooks to one workbook but I don't know how to do that using openXML. I only want to create one workbook with two worksheet. I don't need merge worksheets to one. How to aggregate two worksheets to one workbook using openXML?
Copying a worksheet from one workbook to another is easy with Epplus which is available free in Nuget.
Something like this example would copy a worksheet & all it's data from one workbook to another in one go without the need for any separate function to loop over the rows to copy the data:
FileInfo fInfoSrc = new FileInfo(#"C:\Temp\Source.xlsx");
FileInfo fInfoDest = new FileInfo(#"C:\Temp\Destination.xlsx");
using (var source = new ExcelPackage(fInfoSrc))
{
using (var destination = new ExcelPackage(fInfoDest))
{
var srcWorksheet = source.Workbook.Worksheets["SourceWorksheet"];
var destWorksheet = destination.Workbook.Worksheets.Add("destinationWorksheetName", srcWorksheet);
destination.Save();
}
}
You need a reference to the OpenXml SDK.
A small example how to create a workbook.
Call the second method AddWorksheet as many worksheets you need.
private static SpreadsheetDocument CreateWorkbook(Stream stream)
{
// Create the Excel workbook
var spreadSheet = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook, false);
// Create the parts and the corresponding objects
// Workbook
spreadSheet.AddWorkbookPart();
spreadSheet.WorkbookPart.Workbook = new Workbook();
spreadSheet.WorkbookPart.Workbook.Save();
// Shared string table
var sharedStringTablePart = spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
sharedStringTablePart.SharedStringTable = new SharedStringTable();
sharedStringTablePart.SharedStringTable.Save();
// Sheets collection
spreadSheet.WorkbookPart.Workbook.Sheets = new Sheets();
spreadSheet.WorkbookPart.Workbook.Save();
// Stylesheet
var workbookStylesPart = spreadSheet.WorkbookPart.AddNewPart<WorkbookStylesPart>();
workbookStylesPart.Stylesheet = new Stylesheet();
workbookStylesPart.Stylesheet.Save();
return spreadSheet;
}
private static WorksheetPart AddWorksheet(SpreadsheetDocument spreadsheet, string name)
{
// Add the worksheetpart
var worksheetPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
uint sheetId = 1;
var sheets = spreadsheet.WorkbookPart.Workbook.GetFirstChild<Sheets>();
if (sheets.Elements<Sheet>().Any())
{
sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;
}
// Add the sheet and make relation to workbook
var sheet = new Sheet
{
Id = spreadsheet.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = sheetId,
Name = name
};
sheets.Append(sheet);
worksheetPart.Worksheet.Save();
spreadsheet.WorkbookPart.Workbook.Save();
return worksheetPart;
}
The best way which I chose is to open destination file and in loop open iteratively source file with worksheet to be copied. Next, I clone each row from source to destination file with clone node method with deep mode. This cloned row I insert in specific index in destination file worksheet.
The good way is to use EPPlus like in other answer to this question but when I use it with excel file where is defined name (named ranges) it does not work correctly.

How to uppercase all the words in excel spreadsheet using NPOI C#

I need to convert all the words conataing in a sheet to uppercase using NPOI in C#; I can't find method to do this.
Before applying uppercase : Cell[1;1]=stackoverflow
After applying uppercase : Cell[1;1]=STACKOVERFLOW
I don't think it is possible without looping through cells using NPOI.Probably it can be done using Interop to Excel since it is possible to select range in file and perform some actions on it (like in Excel), but NPOI doesn't offers such ability.
Howewer, you don't need to loop through all cells in sheet since there exists properties FirstRowNum and LastRowNum and they gives you range of rows actually containing data.
So your loop could look like (converting to uppercase all strings from the first worksheet of file):
var hssfwb;
using (var file = new FileStream(#"your_file.xls", FileMode.Open, FileAccess.Read))
{
hssfwb = new HSSFWorkbook(file);
file.Close();
}
var sheet = hssfwb.GetSheetAt(0);
for (int i = sheet.FirstRowNum; i <= sheet.LastRowNum; i++)
{
var row = sheet.GetRow(i);
if (row != null)
{
foreach (ICell cell in row.Cells.Where(c => c.CellType == CellType.String))
cell.SetCellValue(cell.StringCellValue.ToUpper());
}
}

How to append a new row to an Excel file using C# and ClosedXML?

I should append a new row to an existing Excel file. The task consists of two parts:
Add to non-existing file (works well).
Add to existing file (doesn't work: it doesn't make NEW record, displaying only the old record from "else" body).
Here is my code:
private static void ExportToEXCEL(DataTable dt, string paymentStoryPath)
{
if (File.Exists(paymentStoryPath))
{
XLWorkbook currentWorkbook = new XLWorkbook(paymentStoryPath);
IXLWorksheet currentWsh = currentWorkbook.Worksheet("Payment history");
//IXLCell cellForNewData = index.Cell(index.LastRowUsed().RowNumber() + 1, 1);
IXLRow rowForNewData = currentWsh.Row(currentWsh.LastRowUsed().RowNumber()+1);
rowForNewData.InsertRowsBelow(1);
rowForNewData.Value = dt;
currentWorkbook.Save();
}
else
{
//not exist
XLWorkbook wb = new XLWorkbook();
wb.Worksheets.Add(dt, "Payment history");
wb.SaveAs(paymentStoryPath);
}
}
What is wrong and what should I change in my code?
To add a DataTable use the InsertTable() method:
XLWorkbook currentWorkbook = new XLWorkbook(paymentStoryPath);
IXLWorksheet currentWsh = currentWorkbook.Worksheet("Payment history");
IXLCell cellForNewData = currentWsh.Cell(currentWsh.LastRowUsed().RowNumber() + 1, 1);
cellForNewData.InsertTable(dt);
currentWorkbook.Save();
I've got the following code from one of my projects that inserts a DataTable into Excel.
//insert rows below a range from the cell going table rows down
ws.Range(
cell.Address.RowNumber
, cell.Address.ColumnNumber
, cell.Address.RowNumber + DocDataSet.Tables[tableNo].Rows.Count
, cell.Address.ColumnNumber)
.InsertRowsBelow(DocDataSet.Tables[tableNo].Rows.Count);
//InsertData returns a range covering the inserted data
var ra = ws.Cell(cell.Address.RowNumber, cell.Address.ColumnNumber)
.InsertData(DocDataSet.Tables[tableNo].AsEnumerable());
//apply the style of the table token cell to the whole range
ra.Style = cell.Style;
Its been a while since I wrote it, but as far as I know the idea is, create a range that will cover the rows and columns that will be populated. The Cell object has a InsertData method that can take any IEnumerable source.
You might not need the ws.Range line, I was inserting into a template so I had to create the space first.
I took #raidri example and took it one step further where I have an extension method to handle this.
public static class Extensions
{
public static void ToExcelFile(this DataTable dataTable, string filename, string worksheetName = "Sheet1")
{
using(var workbook = new XLWorkbook())
{
workbook.Worksheets.Add(dataTable, worksheetName);
workbook.SaveAs(filename);
}
}
}
Use
myDataTable.ToExcelFile(#"C:\temp\myFile.xlsx");

How to add values to a spreadsheet from a dictionary?

I have a template spreadsheet document that has two columns, Server Name and IP Address.
How can I populate the spreadsheet so that each dictionary key goes in its own cell in the Server column and the corresponding value goes in the cell next to it in the IP column?
I am using the EPPlus library but couldn't find anything on the topic.
Below is what I found and tried, but its for lists
using (ExcelPackage package = new ExcelPackage(_fileInfo))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
for (int i = 0; i < listOfIPs.Count; i++)
{
worksheet.Cells[i + 2, 1].Value = listOfIPs[i];
}
package.Save();
}
I am not familiar with EPPlus, therefore I am not sure how you get the reference to the active sheet - you need to figure out this bit though once that's done pure C# with a bit of knowledge about VBA model and you can easily avoid any iterations to get contents of your dictionary to a spreadsheet:
// create a sample dictionary and fill it
Dictionary<string, string> myCol = new Dictionary<string, string>();
myCol.Add("server1", "ip1");
myCol.Add("server2", "ip2");
// grab a reference to the active Sheet
// this may vary depending on what framework you are using
Worksheet ws = Globals.ThisWorkbook.ActiveSheet as Worksheet;
// create a Range variable
Range myRange;
// Transpose the keys to column A
myRange = ws.get_Range("A1");
myRange.get_Resize(myCol.Keys.ToArray().Count(),1).Value =
ws.Parent.Parent.Transpose(myCol.Keys.AsEnumerable().ToArray());
// transpose the Values to column B
myRange = ws.get_Range("B1");
myRange.get_Resize(myCol.Values.ToArray().Count(), 1).Value =
ws.Parent.Parent.Transpose(myCol.Values.AsEnumerable().ToArray());
Debugging results as expected
With EPPlus I think you can do it like this (untested)
using (ExcelPackage package = new ExcelPackage(file))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("test");
worksheet.Cells["A1"].LoadFromCollection(myColl, true, OfficeOpenXml.Table.TableStyles.Medium);
package.Save();
}
More details on VBA Collections iterations and printing to Sheet # vba4all.com
You can just access the keys of a dictionary and iterate over them just like you are iterating over the list.
var foo = new Dictionary<string, string>(); // populate your dictionary
foreach(var key in foo.Keys)
{
var value = foo[key];
// do stuff with 'key' and 'value', like put them into the excel doc
}

Get Tables (workparts) of a sheet of excel by OpenXML SDK

I have 3 tables in a sheet of excel file,
and I use OpenXML SDK to read the Excel file, like this:
SpreadSheetDocument document = SpreadSheetDDocument.open(/*read it*/);
foreach(Sheet sheet in document.WorkbookPart.Workbook.Sheets)
{
//I need each table or work part of sheet here
}
So as you see I can get each sheet of Excel, but how can I get workparts in each sheet, like my 3 tables I should can iterate on these tables, does any one know about this? any suggestion?
Does this help?
// true for editable
using (SpreadsheetDocument xl = SpreadsheetDocument.Open("yourfile.xlsx", true))
{
foreach (WorksheetPart wsp in xl.WorkbookPart.WorksheetParts)
{
foreach (TableDefinitionPart tdp in wsp.TableDefinitionParts)
{
// for example
// tdp.Table.AutoFilter = new AutoFilter() { Reference = "B2:D3" };
}
}
}
Note that the actual cell data is not in the Table object, but in SheetData (under Worksheet of the WorksheetPart). Just so you know.
You can get the specific table from excel. Adding more to the answer of #Vincent
using (SpreadsheetDocument document= SpreadsheetDocument.Open("yourfile.xlsx", true))
{
var workbookPart = document.WorkbookPart;
var relationsShipId = workbookPart.Workbook.Descendants<Sheet>()
.FirstOrDefault(s => s.Name.Value.Trim().ToUpper() == "your sheetName")?.Id;
var worksheetPart = (WorksheetPart)workbookPart.GetPartById(relationsShipId);
TableDefinitionPart tableDefinitionPart = worksheetPart.TableDefinitionParts
.FirstOrDefault(r =>
r.Table.Name.Value.ToUpper() =="your Table Name");
QueryTablePart queryTablePart = tableDefinitionPart.QueryTableParts.FirstOrDefault();
Table excelTable = tableDefinitionPart.Table;
var newCellRange = excelTable.Reference;
var startCell = newCellRange.Value.Split(':')[0]; // you can have your own logic to find out row and column with this values
var endCell = newCellRange.Value.Split(':')[1];// Then you can use them to extract values using regular open xml
}

Categories

Resources