Click here to Skip to main content
Click here to Skip to main content

Reusable Class to Generate Excel Files

By , 20 Mar 2009
 

Introduction

So far I haven't met any developer that has not, at some point in his/her career, had the need to export or display data in an Excel file. There are hundreds of samples of different ways to achieve this all over the web, including The Code Project. Unfortunately I've never seen anything about a class that can be reused in different scenarios.

Fortunately, starting with Excel 2003, we can create an XML file with particular formatting and it will be opened as an Excel file. There are several ways to create an XML document, you can use the System.Xml namespace, concatenate strings or use a string builder (I don't recommend it, but it's possible) but, now you can use LINQ to XML and creating XML becomes so easy it's almost not fun anymore. 

Limitations of the Code 

Like I said, this works starting with Excel 2003 and later so, if you still have Office XP then you're out of luck.

Also this code is restricted to Excel's limitations. That is, it cannot handle more than 256 columns or 65,000 rows. 

Using the Code 

This is just a single class called XmlExcelHelper that contains all the methods to add Worksheets, Rows, Cells, and even Styles for strings to the new file. You need the System.Xml, System.Xml.Linq, and System.Core namespaces for it to work. 

Almost every method, including the class' constructor have several overloads, I'll demonstrate how to use some of them and you can play with the rest. The class is fully documented and I think is very straightforward. Explaining the XML nodes that Excel needs is beyond the scope of this article. 

The XmlExcelHelper's constructors call a private method called CreateExcelHeader. This method adds the XML structure that makes the created file to be an Excel file and I would like to thank Ming_Lu whose article located here gave me everything that was needed to create this class.

Here is a small example of how we can use this class to feed data into the XML and create a nice Excel table. I'm creating  a dummy DataTable, but you can use custom objects, Datasets or anything that has data that you need to save as an Excel file.   

private const string TABLE_HEADER_FORMAT_NAME = "greyBackground";
private const string SMALL_FONT_FORMAT = "smallFont";
private static DataTable CreateDataTable()
{
    DataTable companies = new DataTable("Companies");
    DataColumn column;
    column = new DataColumn("CompanyName");
    companies.Columns.Add(column);
    column = new DataColumn("CompanyCountry");
    companies.Columns.Add(column);
    column = new DataColumn("YearSales");
    companies.Columns.Add(column);
    column = new DataColumn("GrossProfit");
    companies.Columns.Add(column);
    column = new DataColumn("CreationDate");
    companies.Columns.Add(column);
    companies.Rows.Add("Mexican Tequila", "Mexico", "10875600", 
			"4975200", "03/24/1995 2:35:00PM");
    companies.Rows.Add("Canadian Food", "Canada", "308450870", 
			"103476200", "08/12/1983");
    companies.Rows.Add("French Wines", "France", "285309567", 
			"81650000", "11/21/1990 17:40:00");
    companies.Rows.Add("German Beer", "Germany", "285309567", 
			"81650000", "11/21/1990 17:40:00");
    companies.Rows.Add("Russian Vodka", "Russia", "285309567", 
			"81650000", "11/21/1990 17:40:00");
    companies.Rows.Add("Spanish Paella", "Spain", 
			"285309567", "81650000", "11/21/1990 17:40:00");
    companies.Rows.Add("Argentinian Beef", "Argentina", 
			"285309567", "81650000", "11/21/1990 17:40:00");
    companies.Rows.Add("Italian Pasta", "Italy", 
			"285309567", "81650000", "11/21/1990 17:40:00");
    return companies;
}
 public static void CreateReport()
{
    DataTable table = CreateDataTable();
    XmlExcelHelper helper = new XmlExcelHelper
		(@"c:\MyExcelTest.xml", "Times New Roman", 11);
    helper.AddStringStyle(TABLE_HEADER_FORMAT_NAME, 
		"Arial", 10, "#FFFFFF", "#C0C0C0", false);
    helper.AddStringStyle(SMALL_FONT_FORMAT, "Arial", 8, "#000000", false);
    helper.CreateSheet("International Foods");
    helper.AddRow();
    helper.AddCell(XmlExcelHelper.CellType.String, "Report Generated with LINQ to XML");
    helper.AddRow();
    helper.AddCell(XmlExcelHelper.CellType.String, 
	SMALL_FONT_FORMAT, "Report generated on " + DateTime.Now.ToLongDateString());
    helper.AddRow();
    foreach (DataColumn column in table.Columns)
    {
        helper.AddCell(XmlExcelHelper.CellType.String, 
		TABLE_HEADER_FORMAT_NAME, column.ColumnName);
    }
    foreach (DataRow row in table.Rows)
    {
        helper.AddRow();
        helper.AddCell(XmlExcelHelper.CellType.String, row[0].ToString());
        helper.AddCell(XmlExcelHelper.CellType.String, row[1].ToString());
        helper.AddCell(XmlExcelHelper.CellType.Number, 
		XmlExcelHelper.DefaultStyles.Decimal, row[2].ToString());
        helper.AddCell(XmlExcelHelper.CellType.Number, 
		XmlExcelHelper.DefaultStyles.Decimal, row[3].ToString());
        helper.AddCell(XmlExcelHelper.CellType.String, row[4].ToString());
    }
    helper.SaveDocument();
}	

As you can see, the class has a SaveDocument method to save the XML file to disk. It also has an ExcelFileXml property which holds the XML string so, if you need to display the Excel file from a Web application in your web page, you would have to do something like this: 

Response.Clear();
Response.AppendHeader("Content-Type", "application/vnd.ms-excel");
Response.AppendHeader("Content-disposition", "attachment; filename=" + helper.FileName);
Response.Write(helper.ExcelFileXml);
Response.Flush();
Response.End();

Points of Interest

Of course this class is just a functional way of creating an Excel file. It has a lot of functionality, you can add several worksheets, add different styles for strings, merge several cells but it could do a lot more. If there's something in particular that you need, you just have to do what you want in Excel, save it as XML and open it to see how the XML looks and you can add it to the class. 

Hopefully you'll find this useful. Have fun.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sergio Romero
Software Developer (Senior)
Mexico Mexico
Member
Sergio has been working as a software developer since 2002 in several industries such as Insurance, Health, and Oil. He is an MCAD and most likely will be looking to upgrade his certification soon.
 
He currently lives in Montreal, Canada.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionAddtionsmemberPetersi14 Jun '12 - 8:50 
Hi;
 
I have made some addtions to the class to allow generic row/cell identification and loading. Let me know if you would like to send it to you for review and possible inclusion into your article.
 
Peter
GeneralMy vote of 5memberNazmul108924 Apr '11 - 1:20 
you have done an excellent job.it helps me reporting by an excel file and i can also report by using the database.Thank You.
GeneralStylesmemberjmvallejo11 Feb '10 - 11:30 
Hi, i'm wondering how to add new styles to the worksheet. The code that generates each style looks like this:
 
new XElement(_MainNamespace + "Style",
new XAttribute(_ss + "ID", "Default"),
new XAttribute(_ss + "Name", "Normal"),
new XElement(_MainNamespace + "Alignment",
new XAttribute(_ss + "Vertical", "Bottom"),
new XAttribute(_ss + "WrapText", "1")
),
 
I already changed the styles using Excel to see how the changes were reflected, and each style looks something like this in xml:
 
<Style ss:ID="s62">
<Font ss:FontName="Arial" x:Family="Swiss" ss:Color="#000000" ss:Bold="1"/>
</Style>
 
Alright what i would like to know is when do you assign the ss:ID="s62" ? when i search the document for the IDs that are being assigned in code (say "Default") i can't find them. So where are they being generated? new XAttribute(_ss + "ID", "Default") doesn't seem to reflect the "Default" part, i guess i'm a little bit confused.
 
Can anybody help me out please?
 
Cheers
QuestionWhich versions of office is this format supposed to work with?memberpopodeperro30 Jan '10 - 5:24 
Sergio, first of all thanks for this class, it is saving me a lot of work and it's very well organized.
 
I'm generating some reports which work great but my client has office 2003 (i guess it supports xml in this format) and she says still can't open the file. Any clues?
 
Thank you
GeneralPerformance improvementmemberClutchplate10 Apr '09 - 7:02 
Great class. I used it as a starting point for some Excel export I needed.
 
Unfortunately, the performance of this class as-is is abysmally poor for non-trivial files (more than a couple of lines) Frown | :( . I was trying to export 4000 lines and it took forever. The reason is that in every .AddXXX function there is a call to set ExcelFileXml to the string representation of the DOM. This is totally unneccesary.
After removing all these calls, deleteing the Setter on ExcelFileXml, it is now much faster.... not as fast as CSV, but we do get all the formatting options. Big Grin | :-D
 
I made some other improvements, like allowing the column widths, Row heights and cell alignment to be specified. Let me know if you're interested in my changes.
 
- Lutz
GeneralRe: Performance improvementmembermirage4566 May '09 - 4:35 
I agree with Lutz, this is a great class. Your performance improvement tip is great too.
 
If you want to go a step farther and improve the performance even more, I would suggest the following:
 
-Change your AddRow functions to return the row.
public XElement AddRow(string style)
 
-Add overloads to all of the AddCell functions to accept the row
public void AddCell(CellType type, string value, XElement row)
public void AddCell(CellType type, string value, int mergeAcrossCells)
public void AddCell(CellType type, string value, int mergeAcrossCells,  XElement row)
...
 
This allows you to not have to lookup the row on every AddCell call, and it drastically improved performance for me as I was exporting a many column table with 40,000+ rows.
 
-Brandon
GeneralRe: Performance improvementmemberjmvallejo12 Feb '10 - 3:24 
Hi Lutz i'm very interested in your changes, would you send them to me? jmvallejo@gmail.com
 
Also i need to add new styles but still can't figure out how, i tried adding a new element under styles and now my Excel shows an error when opening the file.
 
Not sure how that works, thanks in advance Smile | :)
GeneralRe: Performance improvementmemberAnandChavali30 Sep '12 - 9:36 
Can you please post your code for allowing widths and heights?
Thanks and Regards,
Anand.

QuestionI want to display the MyExcelTest.xml in web page ?memberJLKEngine00820 Mar '09 - 17:07 
I want to display the MyExcelTest.xml in web page ?
 
ExcelGeneratingClass.XmlExcelHelper helper = new ExcelGeneratingClass.XmlExcelHelper();
string sFileName = @"c:\MyExcelTest.xml";
helper.FileName = sFileName;
 
string sExcelFileXml = helper.ExcelFileXml;
 
Response.Clear();
Response.AppendHeader("Content-Type", "application/vnd.ms-excel");
Response.AppendHeader("Content-disposition", "attachment; filename=" + sFileName);
Response.Write(sExcelFileXml);
Response.Flush();
Response.End();
AnswerRe: I want to display the MyExcelTest.xml in web page ?memberSergio Romero22 Mar '09 - 4:53 
I'm not sure I understand what kind of help do you need.
 
With this code you should be able to get your Excel file to be opened in your web page. Do you get any error messages?
Questioncan you help me?memberJLKEngine00820 Mar '09 - 17:07 
I want to dispaly the MyExcelTest.xml in web page ?
 
ExcelGeneratingClass.XmlExcelHelper helper = new ExcelGeneratingClass.XmlExcelHelper();
string sFileName = @"c:\MyExcelTest.xml";
helper.FileName = sFileName;
 
string sExcelFileXml = helper.ExcelFileXml;
 
Response.Clear();
Response.AppendHeader("Content-Type", "application/vnd.ms-excel");
Response.AppendHeader("Content-disposition", "attachment; filename=" + sFileName);
Response.Write(sExcelFileXml);
Response.Flush();
Response.End();
AnswerRe: can you help me?memberCikaPero28 Feb '10 - 21:57 
Hi,
 
if you want to display xml file in web page in friendly way you will have to use XML transformations to convert your data to HTML. Take a look at W3Schools XLS Transformations.
 
If you are looking a way to export Excel file to browser, use this Excel C# library - because it is very fast, easy to use & doesn't use Excel Interop.
Questioncan you saving an Excel file with a chart as an XML file ?memberJLKEngine00820 Mar '09 - 17:01 
It is very good! but I want to save an Excel file with a chart as an XML file, can you help me ? thanks! hy2001al@163.com
AnswerRe: can you saving an Excel file with a chart as an XML file ?memberSergio Romero22 Mar '09 - 4:51 
Unfortunately you can't. As soon as you try to save an Excel file with a chart on it as XML, the chart is not created.
 
It seems that there are no XML tags to represent a chart for an Excel file.
 
Sorry.
GeneralNice Codememberobinna_eke18 Mar '09 - 3:24 
Can you embed a chart or an image as well?
Thumbs Up | :thumbsup:
GeneralRe: Nice CodememberSergio Romero18 Mar '09 - 14:50 
You probably can but I guess it would make a very nasty XML.
 
Like I said you can create a chart on Excel, save the file as XML and open it in notepad or any XML editor to look at how that would work.
 
I'll try it out and see how that goes.
GeneralRe: Nice CodememberSergio Romero19 Mar '09 - 4:52 
Hi,
 
I tried saving an Excel file with a chart as an XML file and, unfortunately, the chart section was taken out.
 
This is too bad because it would have been nice, now I'm sorry to say that if you need a chart in your file you'll have to use another solution.
 
Sorry.
 
:(

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 20 Mar 2009
Article Copyright 2009 by Sergio Romero
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid