Click here to Skip to main content
Email Password   helpLost your password?

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

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralStyles applied to cells
Budsy
13:58 27 Feb '09  
What would be the way to add styles to cells, such as BOLD or CENTERED?
GeneralRe: Styles applied to cells
ColinBashBash
4:24 2 Mar '09  
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>");

GeneralDoes this code works when there is no excel in server ?
srinivasanvk
2:30 20 Jan '09  
Hi,
Can you please tell me does this code works without the
Excel installed in the server?

by

Srinivasan V
GeneralRe: Does this code works when there is no excel in server ?
ColinBashBash
4:23 20 Jan '09  
Yes. It works fine without Excel installed.
Questionis it possible to pass a macro - 'format as table'
Ric29
13:09 13 Jan '09  
Is there a way to 'format as table' w/ the XmlTextWriter?
Thanks.
AnswerRe: is it possible to pass a macro - 'format as table'
ColinBashBash
5:46 14 Jan '09  
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 Message
ndennisv
4:01 13 Jan '09  
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 Message
ColinBashBash
5:15 13 Jan '09  
add this code:

using System.Collections;
RantXmlTextWriter
jonnyroyster
1:03 13 Jan '09  
If your going to use XmlWriters, don't use WriteRaw otherwise you may as well just use a StreamWriter or similar, always use the correct in built methods. Other than that, this is not a bad example of using the office Xml formats.
GeneralGood work
Dr.Luiji
0:16 13 Jan '09  
Very interesting article Colin, thanks for sharing,
(I like you fonts a lot)
Have a 5 !!

Dr.Luiji

Trust and you'll be trusted.

Try iPhone UI [^] a new fresh face for your Windows Mobile, here on Code Project.

GeneralYou can also use Transform function of XslCompliedTransform class in .Net Framework to complete this work
songjietoo
20:57 6 Jan '09  
That is good!Microsoft already provides the function. Big Grin
GeneralRe: You can also use Transform function of XslCompliedTransform class in .Net Framework to complete this work
ColinBashBash
4:19 7 Jan '09  
I'm not sure which way you're going with this. Is this what you were thinking?

DataSet --> XML --> XSLT Processor --> Excel XML

-- I had problems with this when dealing with null data. Excel needs to know the column index, and the XML from the dataset drops the column indexes...


Last Updated 21 Jan 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010