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

Output DataSet to Excel

By , 21 Jan 2009
 

Introduction

I did this when I wanted to do a quick export of an entire DataSet (multiple tables) to Excel. I didn't add any additional customization to the fields, but I did want to make sure that dates, boolean, numbers, and text were all formatted correctly.

This code does that.

At some point, I'd like to make a GridView type component that would allow me to detail more about each item. For example, my latest project required me to make a column formatted with a given barcode font ("Free 3 of 9") that required that I put an * before and after the item number. The solution below doesn't make this easy to do, though... So yeah, not perfect. If anyone else has done something like this, let me know :)

For importing Excel to XML, see this post.

NOTE: This method does NOT require Excel to be installed on the Server.

Background

I prefer to see each table in the DataSet to be named.

ds.Tables[0].TableName = "Colors";
ds.Tables[1].TableName = "Shapes";

I changed it to allow you to pass in a List<Table> in case you don't put them in a DataSet. No big deal either way.

Why did I use an XmlTextWriter when I seem to be only using the WriteRaw? I wanted to be able to have it fix any special characters with the "x.WriteString(row[i].ToString());". Note, this still may have problems with certain characters, since I haven't tested it much.

Using the Code

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Xml;

public void Convert(DataSet ds, string fileName) {
    Convert(ds.Tables, fileName);
}
public void Convert(IEnumerable tables, string fileName) {
    Response.ClearContent();
    Response.ClearHeaders();
    Response.Buffer = true;
    Response.Charset = "";
    Response.ContentType = "application/vnd.ms-excel";
    Response.AddHeader("content-disposition", 
             "attachment; filename=" + fileName + ".xls");

    using (XmlTextWriter x = new XmlTextWriter(Response.OutputStream, Encoding.UTF8)) {
        int sheetNumber = 0;
        x.WriteRaw("<?xml version=\"1.0\"?><?mso-application progid=\"Excel.Sheet\"?>");
        x.WriteRaw("<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" ");
        x.WriteRaw("xmlns:o=\"urn:schemas-microsoft-com:office:office\" ");
        x.WriteRaw("xmlns:x=\"urn:schemas-microsoft-com:office:excel\">");
        x.WriteRaw("<Styles><Style ss:ID='sText'>" + 
                   "<NumberFormat ss:Format='@'/></Style>");
        x.WriteRaw("<Style ss:ID='sDate'><NumberFormat" + 
                   " ss:Format='[$-409]m/d/yy\\ h:mm\\ AM/PM;@'/>");
        x.WriteRaw("</Style></Styles>");
        foreach (DataTable dt in tables) {
            sheetNumber++;
            string sheetName = !string.IsNullOrEmpty(dt.TableName) ? 
                   dt.TableName : "Sheet" + sheetNumber.ToString();
            x.WriteRaw("<Worksheet ss:Name='" + sheetName + "'>");
            x.WriteRaw("<Table>");
            string[] columnTypes = new string[dt.Columns.Count];

            for (int i = 0; i < dt.Columns.Count; i++) {
                string colType = dt.Columns[i].DataType.ToString().ToLower();

                if (colType.Contains("datetime")) {
                    columnTypes[i] = "DateTime";
                    x.WriteRaw("<Column ss:StyleID='sDate'/>");

                } else if (colType.Contains("string")) {
                    columnTypes[i] = "String";
                    x.WriteRaw("<Column ss:StyleID='sText'/>");

                } else {
                    x.WriteRaw("<Column />");

                    if (colType.Contains("boolean")) {
                        columnTypes[i] = "Boolean";
                    } else {
                        //default is some kind of number.
                        columnTypes[i] = "Number";
                    }

                }
            }
            //column headers
            x.WriteRaw("<Row>");
            foreach (DataColumn col in dt.Columns) {
                x.WriteRaw("<Cell ss:StyleID='sText'><Data ss:Type='String'>");
                x.WriteRaw(col.ColumnName);
                x.WriteRaw("</Data></Cell>");
            }
            x.WriteRaw("</Row>");
            //data
            bool missedNullColumn = false;
            foreach (DataRow row in dt.Rows) {
                x.WriteRaw("<Row>");
                for (int i = 0; i < dt.Columns.Count; i++) {
                    if (!row.IsNull(i)) {
                        if (missedNullColumn) {
                            int displayIndex = i + 1;
                            x.WriteRaw("<Cell ss:Index='" + displayIndex.ToString() + 
                                       "'><Data ss:Type='" + 
                                       columnTypes[i] + "'>");
                            missedNullColumn = false;
                        } else {
                            x.WriteRaw("<Cell><Data ss:Type='" + 
                                       columnTypes[i] + "'>");
                        }

                        switch (columnTypes[i]) {
                            case "DateTime":
                                x.WriteRaw(((DateTime)row[i]).ToString("s"));
                                break;
                            case "Boolean":
                                x.WriteRaw(((bool)row[i]) ? "1" : "0");
                                break;
                            case "String":
                                x.WriteString(row[i].ToString());
                                break;
                            default:
                                x.WriteString(row[i].ToString());
                                break;
                        }

                        x.WriteRaw("</Data></Cell>");
                    } else {
                        missedNullColumn = true;
                    }
                }
                x.WriteRaw("</Row>");
            }
            x.WriteRaw("</Table></Worksheet>");
        }
        x.WriteRaw("</Workbook>");
    }
    Response.End();
}

History

  • Jan 7, 2009: Added link about importing (see Introduction).
  • Jan 8, 2009: Updated link about importing (see Introduction).
  • Jan 21, 2009: Added note about Excel not being required on the server

License

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

About the Author

ColinBashBash
Software Developer
United States United States
Member
likes boardgames, computer games, and enjoys his .net programming job.

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   
Generalfloat / double - use dot instead of comma (for German installations) [modified]memberSina Falahati21 Aug '10 - 9:51 
Double / float is exported incorrectly I noticed on my C# installation, which is in German:
 
Be careful: 1,123 is the same as 1123 for Excel.
1.123 is interpreted correctly as a number smaller than 2.
 
It seems that not in all languages the interpretation is the same for ToString();
 
therefore use:
.ToString(CultureInfo.InvariantCulture.NumberFormat);
 
where it applies.
 
Explaining InvariantCulture[^]
 
Thanks for the article. You have written a great piece of code Thumbs Up | :thumbsup:

modified on Saturday, August 21, 2010 4:00 PM

GeneralStyles applied to cellsmemberBudsy27 Feb '09 - 12:58 
What would be the way to add styles to cells, such as BOLD or CENTERED?
GeneralRe: Styles applied to cellsmemberColinBashBash2 Mar '09 - 3:24 
First, in the styles declaration, I would add this one:
"<Style ss:ID='sHeader'><Alignment ss:Horizontal='Center' /><Font ss:Bold='1'/><NumberFormat ss:Format='@'/></Style>"
Then update the column headers to use sHeader instead of sText. Make sense? (I'm assuming you want this for just the column headers.)
x.WriteRaw("<Row>");
foreach (DataColumn col in dt.Columns) {
    x.WriteRaw("<Cell ss:StyleID='sHeader'><Data ss:Type='String'>");
    x.WriteRaw(col.ColumnName);
    x.WriteRaw("</Data></Cell>");
}
x.WriteRaw("</Row>");

QuestionDoes this code works when there is no excel in server ?membersrinivasanvk20 Jan '09 - 1:30 
Hi,
Can you please tell me does this code works without the
Excel installed in the server?
 
by
 
Srinivasan V
AnswerRe: Does this code works when there is no excel in server ?memberColinBashBash20 Jan '09 - 3:23 
Yes. It works fine without Excel installed.
AnswerRe: Does this code works when there is no excel in server ?memberCikaPero4 Sep '11 - 21:17 
If you require more control when importing DataSet to Excel, without Excel Interop, you should try this Excel C# / VB.NET library.
 
Here is an Excel C# sample how to import DataSet to Excel with it:
var ef = new ExcelFile();
 
foreach (DataTable dataTable in dataSet.Tables)
    ef.Worksheets.Add(dataTable.TableName).InsertDataTable(dataTable, 0, 0, true);
 
ef.SaveXls(dataSet.DataSetName + ".xls");

Questionis it possible to pass a macro - 'format as table'memberRic2913 Jan '09 - 12:09 
Is there a way to 'format as table' w/ the XmlTextWriter?
Thanks.
AnswerRe: is it possible to pass a macro - 'format as table'memberColinBashBash14 Jan '09 - 4:46 
Sorry, Excel XML format does not support macros. You'll have to use the excel XLS format... google for "adding excel macros programmatically" Smile | :)
GeneralGetting Error Messagememberndennisv13 Jan '09 - 3:01 
I'm new to this, so I just copied and pasted the code.
 
I'm getting this error message:
 
Using the generic type 'System.Collections.Generic.IEnumerable<T>' requires '1' type arguments
 
On this line:
 
public void Convert(IEnumerable tables, string fileName)
 
where IEnumerable is underlined.
 
VS2005 - C#
 
Thanks,
 
Dennis
GeneralRe: Getting Error MessagememberColinBashBash13 Jan '09 - 4:15 
add this code:
 
using System.Collections;

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 21 Jan 2009
Article Copyright 2009 by ColinBashBash
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid