ASP.NETアプリ(VB.NETコードビハインド)にセクションを追加して、ユーザーがデータをExcelファイルとして取得し、データベースデータに基づいて生成できるようにします。これにはいくつかの方法がありますが、それぞれに欠点があります。 yoはどのようにデータを返しますか?できる限りクリーンで簡単なものを探しています。
長所:
短所:
長所:
短所:
長所:
短所:
長所:
短所:
長所:
短所:
長所:
短所:
データをhtmlテーブルセルとして出力し、.xls
または.xlsx
拡張子が付けられ、Excelはネイティブドキュメントであるかのように開きます。この方法で制限された書式設定や式の計算を行うこともできるため、CSVよりもはるかに強力です。また、htmlテーブルの出力は、ASP.NetなどのWebプラットフォームから非常に簡単に実行できるはずです;)
Excelワークブック内に複数のワークシートまたは名前付きワークシートが必要な場合は、SpreadSheetML
というXMLスキーマを介して同様のことができます。これはnot Office 2007に同梱された新しい形式ですが、Excel 2000にまでさかのぼって完全に異なるものです。どのように機能するかを説明する最も簡単な方法は例です:
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-Microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-Microsoft-com:office:office"
xmlns:x="urn:schemas-Microsoft-com:office:Excel"
xmlns:ss="urn:schemas-Microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-Microsoft-com:office:office">
<Author>Your_name_here</Author>
<LastAuthor>Your_name_here</LastAuthor>
<Created>20080625</Created>
<Company>ABC Inc</Company>
<Version>10.2625</Version>
</DocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-Microsoft-com:office:Excel">
<WindowHeight>6135</WindowHeight>
<WindowWidth>8445</WindowWidth>
<WindowTopX>240</WindowTopX>
<WindowTopY>120</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom" />
<Borders />
<Font />
<Interior />
<NumberFormat />
<Protection />
</Style>
</Styles>
<Worksheet ss:Name="Sample Sheet 1">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table1">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
<Cell><Data ss:Type="Number">1</Data></Cell>
<Cell><Data ss:Type="Number">2</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">3</Data></Cell>
<Cell><Data ss:Type="Number">4</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">5</Data></Cell>
<Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">7</Data></Cell>
<Cell><Data ss:Type="Number">8</Data></Cell>
</Row>
</Table>
</Worksheet>
<Worksheet ss:Name="Sample Sheet 2">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table2">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
<Cell><Data ss:Type="String">A</Data></Cell>
<Cell><Data ss:Type="String">B</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">C</Data></Cell>
<Cell><Data ss:Type="String">D</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">E</Data></Cell>
<Cell><Data ss:Type="String">F</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">G</Data></Cell>
<Cell><Data ss:Type="String">H</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook>
DataTableから来る場合:
public static void DataTabletoXLS(DataTable DT, string fileName)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Charset = "utf-16";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.xls", fileName));
HttpContext.Current.Response.ContentType = "application/ms-Excel";
string tab = "";
foreach (DataColumn dc in DT.Columns)
{
HttpContext.Current.Response.Write(tab + dc.ColumnName.Replace("\n", "").Replace("\t", ""));
tab = "\t";
}
HttpContext.Current.Response.Write("\n");
int i;
foreach (DataRow dr in DT.Rows)
{
tab = "";
for (i = 0; i < DT.Columns.Count; i++)
{
HttpContext.Current.Response.Write(tab + dr[i].ToString().Replace("\n", "").Replace("\t", ""));
tab = "\t";
}
HttpContext.Current.Response.Write("\n");
}
HttpContext.Current.Response.End();
}
Gridviewから:
public static void GridviewtoXLS(GridView gv, string fileName)
{
int DirtyBit = 0;
int PageSize = 0;
if (gv.AllowPaging == true)
{
DirtyBit = 1;
PageSize = gv.PageSize;
gv.AllowPaging = false;
gv.DataBind();
}
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Charset = "utf-8";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
HttpContext.Current.Response.AddHeader(
"content-disposition", string.Format("attachment; filename={0}.xls", fileName));
HttpContext.Current.Response.ContentType = "application/ms-Excel";
using (StringWriter sw = new StringWriter())
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// Create a table to contain the grid
Table table = new Table();
// include the gridline settings
table.GridLines = gv.GridLines;
// add the header row to the table
if (gv.HeaderRow != null)
{
Utilities.Export.PrepareControlForExport(gv.HeaderRow);
table.Rows.Add(gv.HeaderRow);
}
// add each of the data rows to the table
foreach (GridViewRow row in gv.Rows)
{
Utilities.Export.PrepareControlForExport(row);
table.Rows.Add(row);
}
// add the footer row to the table
if (gv.FooterRow != null)
{
Utilities.Export.PrepareControlForExport(gv.FooterRow);
table.Rows.Add(gv.FooterRow);
}
// render the table into the htmlwriter
table.RenderControl(htw);
// render the htmlwriter into the response
HttpContext.Current.Response.Write(sw.ToString().Replace("£", ""));
HttpContext.Current.Response.End();
}
if (DirtyBit == 1)
{
gv.PageSize = PageSize;
gv.AllowPaging = true;
gv.DataBind();
}
}
private static void PrepareControlForExport(Control control)
{
for (int i = 0; i < control.Controls.Count; i++)
{
Control current = control.Controls[i];
if (current is LinkButton)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as LinkButton).Text));
}
else if (current is ImageButton)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as ImageButton).AlternateText));
}
else if (current is HyperLink)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as HyperLink).Text));
}
else if (current is DropDownList)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as DropDownList).SelectedItem.Text));
}
else if (current is CheckBox)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as CheckBox).Checked ? "True" : "False"));
}
if (current.HasControls())
{
Utilities.Export.PrepareControlForExport(current);
}
}
}
これはSpreadMLの無料のラッパーです-それは素晴らしい作品です。
与えられた回答と同僚との協議に基づいて、最善の解決策はXMLファイルまたはHTMLテーブルを生成し、それを添付ファイルとしてプッシュダウンすることであると思われます。同僚が推奨する変更の1つは、データ(つまりHTMLテーブル)をResponseオブジェクトに直接書き込むことができることです。これにより、ファイルを書き出す必要がなくなります。これは、アクセス許可の問題、I/O競合、およびスケジュールされたパージが発生することの確認。
ここにコードのスニペットがあります...私はまだこれをチェックしておらず、すべての呼び出されたコードを提供していませんが、それはアイデアをうまく表していると思います。
Dim uiTable As HtmlTable = GetUiTable(groupedSumData)
Response.Clear()
Response.ContentType = "application/vnd.ms-Excel"
Response.AddHeader("Content-Disposition", String.Format("inline; filename=OSSummery{0:ddmmssf}.xls", DateTime.Now))
Dim writer As New System.IO.StringWriter()
Dim htmlWriter As New HtmlTextWriter(writer)
uiTable.RenderControl(htmlWriter)
Response.Write(writer.ToString)
Response.End()
excelはHTMLを理解しているため、データをHTMLテーブルとして.xls拡張子を持つ一時ファイルに書き出すことができ、ファイルのFileInfoを取得して、
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + fi.Name);
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(fi.FullName);
Response.End();
一時ファイルを避けたい場合は、WriteFileを使用する代わりに、メモリ内ストリームに書き込み、バイトを書き戻すことができます。
content-lengthヘッダーが省略されている場合、htmlを直接書き戻すことができますが、これはすべてのブラウザーで常に正しく機能しない場合があります
私は個人的にXMLメソッドを好みます。データセットのデータベースからデータを返し、XMlに保存してから、適切なドキュメントをフォーマットする変換ルールを含むxsltファイルを作成し、単純なXML変換でジョブを完了します。これに関する最も良い部分は、セルの書式設定、条件付き書式設定、ヘッダーとフッターの設定、さらには印刷範囲の設定です。
データグリッドからExcelに常にデータをエクスポートします。 HTMLに変換してからExcelファイルに書き込む
Response.ContentType = "application/vnd.ms-Excel"
Response.Charset = ""
Response.AddHeader("content-disposition", "fileattachment;filename=YOURFILENAME.xls")
Me.EnableViewState = False
Dim sw As System.IO.StringWriter = New System.IO.StringWriter
Dim hw As HtmlTextWriter = New HtmlTextWriter(sw)
ClearControls(grid)
grid.RenderControl(hw)
Response.Write(sw.ToString())
Response.End()
この方法の唯一の落とし穴は、グリッドの多くにボタンまたはリンクが含まれていたため、これも必要なことです。
'needed to export grid to Excel to remove link button control and represent as text
Private Sub ClearControls(ByVal control As Control)
Dim i As Integer
For i = control.Controls.Count - 1 To 0 Step -1
ClearControls(control.Controls(i))
Next i
If TypeOf control Is System.Web.UI.WebControls.Image Then
control.Parent.Controls.Remove(control)
End If
If (Not TypeOf control Is TableCell) Then
If Not (control.GetType().GetProperty("SelectedItem") Is Nothing) Then
Dim literal As New LiteralControl
control.Parent.Controls.Add(literal)
Try
literal.Text = CStr(control.GetType().GetProperty("SelectedItem").GetValue(control, Nothing))
Catch
End Try
control.Parent.Controls.Remove(control)
Else
If Not (control.GetType().GetProperty("Text") Is Nothing) Then
Dim literal As New LiteralControl
control.Parent.Controls.Add(literal)
literal.Text = CStr(control.GetType().GetProperty("Text").GetValue(control, Nothing))
control.Parent.Controls.Remove(control)
End If
End If
End If
Return
End Sub
どこかでうまくいくことがわかりました。
これを数回行いましたが、最も簡単な方法は、CSV(カンマ区切り値)ファイルを返すことでした。 Excelは完全にインポートしますが、実行は比較的高速です。
無料のオープンソースExcel生成ライブラリ OpenXMLに基づいています
それは数ヶ月前に私を助けました。
ストアドプロシージャから取得するレポートを次に示します。結果はExcelにエクスポートされます。 ADO.NETの代わりにADOを使用し、その理由はこの行です
oSheet.Cells(2, 1).copyfromrecordset(rst1)
ほとんどの作業を行い、ado.netでは利用できません。
‘Calls stored proc in SQL Server 2000 and puts data in Excel and ‘formats it
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim cnn As ADODB.Connection
cnn = New ADODB.Connection
cnn.Open("Provider=SQLOLEDB;data source=xxxxxxx;" & _
"database=xxxxxxxx;Trusted_Connection=yes;")
Dim cmd As New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandText = "[sp_TomTepley]"
cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
cmd.CommandTimeout = 0
cmd.Parameters.Refresh()
Dim rst1 As ADODB.Recordset
rst1 = New ADODB.Recordset
rst1.Open(cmd)
Dim oXL As New Excel.Application
Dim oWB As Excel.Workbook
Dim oSheet As Excel.Worksheet
'oXL = CreateObject("Excel.application")
oXL.Visible = True
oWB = oXL.Workbooks.Add
oSheet = oWB.ActiveSheet
Dim Column As Integer
Column = 1
Dim fld As ADODB.Field
For Each fld In rst1.Fields
oXL.Workbooks(1).Worksheets(1).Cells(1, Column).Value = fld.Name
oXL.Workbooks(1).Worksheets(1).cells(1, Column).Interior.ColorIndex = 15
Column = Column + 1
Next fld
oXL.Workbooks(1).Worksheets(1).name = "Tom Tepley Report"
oSheet.Cells(2, 1).copyfromrecordset(rst1)
oXL.Workbooks(1).Worksheets(1).Cells.EntireColumn.AutoFit()
oXL.Visible = True
oXL.UserControl = True
rst1 = Nothing
cnn.Close()
Beep()
End Sub
Microsoft.Office.Interop名前空間を介したCOM相互運用は避けてください。とても遅くて、信頼できず、スケーラブルではありません。マゾには適用されません。
このライブラリを使用して、適切にフォーマットされたExcelファイルを非常に簡単に作成できます。 http://officehelper.codeplex.com/documentation 。
Microsoft OfficeをWebサーバーにインストールする必要はありません!
GridViewにデータを入力すると、この関数を使用してHTML形式のデータを取得できますが、ブラウザーにはExcelファイルであることを示します。
Public Sub ExportToExcel(ByVal fileName As String, ByVal gv As GridView)
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
HttpContext.Current.Response.ContentType = "application/ms-Excel"
Dim sw As StringWriter = New StringWriter
Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
Dim table As Table = New Table
table.GridLines = gv.GridLines
If (Not (gv.HeaderRow) Is Nothing) Then
PrepareControlForExport(gv.HeaderRow)
table.Rows.Add(gv.HeaderRow)
End If
For Each row As GridViewRow In gv.Rows
PrepareControlForExport(row)
table.Rows.Add(row)
Next
If (Not (gv.FooterRow) Is Nothing) Then
PrepareControlForExport(gv.FooterRow)
table.Rows.Add(gv.FooterRow)
End If
table.RenderControl(htw)
HttpContext.Current.Response.Write(sw.ToString)
HttpContext.Current.Response.End()
End Sub
Private Sub PrepareControlForExport(ByVal control As Control)
Dim i As Integer = 0
Do While (i < control.Controls.Count)
Dim current As Control = control.Controls(i)
If (TypeOf current Is LinkButton) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, LinkButton).Text))
ElseIf (TypeOf current Is ImageButton) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, ImageButton).AlternateText))
ElseIf (TypeOf current Is HyperLink) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, HyperLink).Text))
ElseIf (TypeOf current Is DropDownList) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, DropDownList).SelectedItem.Text))
ElseIf (TypeOf current Is CheckBox) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, CheckBox).Checked))
End If
If current.HasControls Then
PrepareControlForExport(current)
End If
i = i + 1
Loop
End Sub
データに基づいてCSVファイルを作成するだけです。なぜなら、それが最もクリーンであり、Excelがそれを適切にサポートしているからです。しかし、より柔軟な形式が必要な場合は、実際のExcelファイルを生成するためのサードパーティツールがいくつかあると確信しています。
CSVが最も簡単な方法です。ほとんどの場合、Excelにリンクされています。それ以外の場合は、自動化APIまたはXML形式を使用する必要があります。 APIとXMLの使用はそれほど難しくありません。
これがイントラネット用であり、アクセス許可を設定してIEを必須とする場合、 JScript/VBScript駆動Excel でワークブッククライアント側を生成できます。これにより、サーバー上でExcelを自動化する手間をかけずに、ネイティブのExcel書式設定が可能になります。
かなりニッチなシナリオを除いて、このアプローチを本当に推奨するかどうかはわかりませんが、古典的なASP最盛期にはかなり一般的でした。
この答え に似ている上記の解決策のいずれかを使用して遭遇した問題の1つは、添付ファイルとしてコンテンツをプッシュする場合です(最もクリーンであることがわかった非msブラウザ用のソリューション)、Excel 2000-2003で開くと、そのタイプは「Excel Webページ」であり、ネイティブのExcelドキュメントではありません。
次に、Excel内から「タイプとして保存」を使用してExcelドキュメントに変換する方法をユーザーに説明する必要があります。ユーザーがこのドキュメントを編集してからサイトに再アップロードする必要がある場合、これは苦痛です。
私の推奨事項は、CSVを使用することです。簡単で、ユーザーがExcel内から開く場合、Excelは少なくともネイティブ形式で保存するように求めます。
上記のようにCSVルートを使用するか、最近ではより頻繁にInfragistics NetAdvantageを使用してファイルを生成します。 (Infragisticsが使用されているほとんどの場合、既存のUltraWebGridをエクスポートするだけです。これは、追加のフォーマット調整が必要でない限り、基本的に1 LOCソリューションです。Excel/ BIFFファイルも手動で生成できます。必要になることはめったにありません。)
男、.netでそれを行うことができるコンポーネントがあると思いますが、古典的なASPでは、すでにHTMLテーブルを作成し、ページのMIMEタイプをvnd/msexcelに変更しました。 gridviewはhtmlテーブルであるため、gridviewを使用してMIMEタイプを変更すると動作するはずです。
「これらの数値はテキストとして保存されているように見える」緑色の三角形を回避する唯一の防弾方法は、Open XML形式を使用することです。避けられない緑色の三角形を避けるために、それを使用する価値があります。
Excelレポートで見た最善の方法は、XML拡張を使用してXMLでデータを書き出し、正しいコンテンツタイプでクライアントにストリーミングすることです。 (application/xls)
これは、基本的な書式設定が必要なレポートで機能し、テキスト比較ツールを使用して既存のスプレッドシートと比較できます。
以下は、データテーブルをCSVとしてストリーム配信するソリューションです。高速、クリーン、簡単、そして入力のコンマを処理します。
public static void ExportToExcel(DataTable data, HttpResponse response, string fileName)
{
response.Charset = "utf-8";
response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
response.Cache.SetCacheability(HttpCacheability.NoCache);
response.ContentType = "text/csv";
response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
for (int i = 0; i < data.Columns.Count; i++)
{
response.Write(data.Columns[i].ColumnName);
response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
}
foreach (DataRow row in data.Rows)
{
for (int i = 0; i < data.Columns.Count; i++)
{
response.Write(String.Format("\"{0}\"", row[i].ToString()));
response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
}
}
response.End();
}
もちろん、サードパーティのコンポーネントをいつでも使用できます。個人的には、Spire.XLSで良い経験をしました http://www.e-iceblue.com/xls/xlsintro.htm
このコンポーネントは、アプリケーション内で非常に簡単に使用できます。
Workbook workbook = new Workbook();
//Load workbook from disk.
workbook.LoadFromFile(@"Data\EditSheetSample.xls");
//Initailize worksheet
Worksheet sheet = workbook.Worksheets[0];
//Writes string
sheet.Range["B1"].Text = "Hello,World!";
//Writes number
sheet.Range["B2"].NumberValue = 1234.5678;
//Writes date
sheet.Range["B3"].DateTimeValue = System.DateTime.Now;
//Writes formula
sheet.Range["B4"].Formula = "=1111*11111";
workbook.SaveToFile("Sample.xls");