Как экспортировать данные JQgrid в Excel, используя C#?
Я провел некоторые исследования по этому вопросу, но большинство решений для MVC... Я просто использую Asp.net 3.5 Как я могу добиться этого при нажатии кнопки... Должен ли я включить какую-либо библиотеку или что-нибудь еще... Пожалуйста, помогите..
3 ответа
Код, который я разместил в ответе, можно использовать практически без каких-либо изменений в любом коде ASP.NET, написанном на C#. Вспомогательный класс DataForExcel
(см. файл DataForExcel.cs
) имеет конструктор
public DataForExcel(string[] headers, List<string[]> data, string sheetName)
или чуть более "продвинутая" версия
public DataForExcel(string[] headers, DataType[] colunmTypes,
List<string[]> data, string sheetName)
которые позволяют указать, какие столбцы имеют числовой тип данных. Параметр List<string[]> data
это данные, которые нужно экспортировать в Excel. Параметр string[] headers
укажите данные для первой строки вывода.
Класс DataForExcel
имеет только один публичный метод
public void CreateXlsxAndFillData(Stream stream)
которые заполняют stream
с двоичным представлением результирующего файла.XLSX Excel.
Чтобы вернуть двоичные данные из вашего метода ASP.NET (например, обработчик ASHX), вам нужно сделать почти то же самое, что и ExecuteResult
из моего ответа:
- создать поток памяти с
using (var stream = new MemoryStream()) {...}
- Создайте
DataForExcel
объект, необходимый для экспорта в Excelvar dataExcel = new DataForExcel (new []{"Id", "Votes", "Title"}, "Questions.xlsx", "Name or Sheet");
response.AddHeader ("content-disposition", "attachment; filename=Questions.xlsx");
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.ContentEncoding = Encoding.UTF8;
stream.WriteTo (response.OutputStream);
response.Flush();
Это все.
ОБНОВЛЕНО: я изменил код, который я разместил ранее, чтобы очень легко создать файл Excel (в формате.xlsx) из сетки. Если вы используете OpenXML SDK 2.0, вы можете использовать.NET 3.5. Для OpenXML SDK 2.5 требуется.NET 4.0 или выше.
Предлагаемый код позволяет конвертировать string[][]
данных в двоичные данные Excel и записать результаты в Stream. Ты можешь использовать MemoryStream
как я описал ранее, чтобы вернуть Excel из любого приложения ASP.NET.
Предлагаемый код содержит ExportToExcel
статический класс с одним открытым статическим методом FillSpreadsheetDocument
который можно использовать следующим образом
var data = new[] {
new [] {"Tom", "30", "x", "", "1974-06-16"},
new [] {"Margarita", "34", "x", "x", "1978-10-02"},
new [] {"Bob", "7", "", "", "2005-06-26"},
new [] {"Oleg", "48", "x", "x", "1964-09-11"},
new [] {"Frank", "29", "", "x", "1983-01-28"}
};
using (var stream = new FileStream("Test.xlsx", FileMode.Create)) {
ExportToExcel.FillSpreadsheetDocument(stream,
new[] {
new ColumnModel { Type = DataType.String, Alignment = HorizontalAlignment.Left, Header = "Name" },
new ColumnModel { Type = DataType.Integer, Header = "Age" },
new ColumnModel { Type = DataType.String, Header = "Is Married", Alignment = HorizontalAlignment.Center, IsRotatedHeader = true },
new ColumnModel { Type = DataType.String, Header = "Has Children", Alignment = HorizontalAlignment.Center, IsRotatedHeader = true },
new ColumnModel { Type = DataType.Date, Header = "Birthday", Alignment = HorizontalAlignment.Left }
},
data,
"Friends");
}
Это производит "Test.xlsx"
с одним листом "Друзья", который выглядит
Ширина столбцов не будет установлена, но в два клика (выберите все и дважды щелкните между столбцами) один пользователь может установить ширину столбцов на оптимальную ширину, как в приведенной выше сборке. Все ячейки имеют отформатированные данные (без "общего" формата). Я использовал целое число, дату и чистые строки. Можно легко создавать столбцы с выравниванием по центру или с выравниванием по правому краю.
Вы можете легко изменить код, чтобы использовать более разные текстовые форматы. Это просто пример того, как создать настоящий документ Excel с отформатированными ячейками.
Рабочий проект Visual Studio 2008 вы можете скачать здесь. Ниже вы найдете исходный код из демо:
using System;
using System.Collections.Generic;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Text;
using System.IO;
using System.Globalization;
namespace ExportToExcel {
public enum ExcelCellDataType {
String,
Integer,
Date
}
public enum HorizontalAlignment {
Left,
Center,
Right
}
public class ColumnModel {
public ExcelCellDataType Type { set; get; }
public HorizontalAlignment Alignment { set; get; }
public string Header { set; get; }
public bool IsRotatedHeader { set; get; }
}
public enum OutputCellFormat: uint {
Text,
Integer,
Date,
TextHeader,
TextHeaderRotated,
TextCenter,
TextRight
}
public static class ExportToExcel {
private static StringBuilder ConvertIntToColumnHeader (uint iCol) {
var sb = new StringBuilder();
while (iCol > 0) {
if (iCol <= 'Z' - 'A') // iCol=0 -> 'A', 25 -> 'Z'
break;
sb.Append(ConvertIntToColumnHeader(iCol / ('Z' - 'A' + 1) - 1));
iCol = iCol % ('Z' - 'A' + 1);
}
sb.Append((char)('A' + iCol));
return sb;
}
private static string GetCellReference (uint iRow, uint iCol) {
return ConvertIntToColumnHeader(iCol).Append(iRow).ToString();
}
private static Row CreateColumnHeaderRow (uint iRow, IList<ColumnModel> colunmModels) {
var r = new Row { RowIndex = iRow };
for (var iCol = 0; iCol < colunmModels.Count; iCol++) {
var styleIndex = colunmModels[iCol].IsRotatedHeader
? (UInt32Value)(uint)(OutputCellFormat.TextHeaderRotated + 1)
: (UInt32Value)(uint)(OutputCellFormat.TextHeader + 1);
r.Append(new OpenXmlElement[] {
// create Cell with InlineString as a child, which has Text as a child
new Cell(new InlineString(new Text { Text = colunmModels[iCol].Header })) {
DataType = CellValues.InlineString,
StyleIndex = styleIndex,
CellReference = GetCellReference(iRow, (uint)iCol)
}
});
}
return r;
}
private static UInt32Value GetStyleIndexFromColumnModel (ColumnModel colunmModel) {
switch (colunmModel.Type) {
case ExcelCellDataType.Integer:
return (uint)(OutputCellFormat.Integer) + 1;
case ExcelCellDataType.Date:
return (uint)(OutputCellFormat.Date) + 1;
}
switch (colunmModel.Alignment) {
case HorizontalAlignment.Center:
return (uint)(OutputCellFormat.TextCenter) + 1;
case HorizontalAlignment.Right:
return (uint)(OutputCellFormat.TextRight) + 1;
default:
return (uint)(OutputCellFormat.Text) + 1;
}
}
private static string ConvertDateToString (string date) {
DateTime dt;
string text = date; // default results of conversion
if (DateTime.TryParse(date, out dt))
text = dt.ToOADate().ToString(CultureInfo.InvariantCulture);
return text;
}
private static Row CreateRow (UInt32 iRow, IList<string> data, IList<ColumnModel> colunmModels, IDictionary<string, int> sharedStrings) {
var r = new Row { RowIndex = iRow };
for (var iCol = 0; iCol < data.Count; iCol++) {
var styleIndex = (uint)(OutputCellFormat.Text) + 1;
string text = data[iCol] ?? String.Empty;
if (colunmModels != null && iCol < colunmModels.Count) {
styleIndex = GetStyleIndexFromColumnModel(colunmModels[iCol]);
switch (colunmModels[iCol].Type) {
case ExcelCellDataType.Integer:
r.Append(new OpenXmlElement[] {
// create Cell with CellValue as a child, which has Text as a child
new Cell(new CellValue { Text = text }) {
StyleIndex = styleIndex,
CellReference = GetCellReference(iRow, (uint)iCol)
}
});
continue;
case ExcelCellDataType.Date:
r.Append(new OpenXmlElement[] {
// create Cell with CellValue as a child, which has Text as a child
new Cell(new CellValue { Text = ConvertDateToString(text) }) {
StyleIndex = styleIndex,
CellReference = GetCellReference(iRow, (uint)iCol)
}
});
continue;
}
}
// default format is text
if (String.IsNullOrEmpty(text) || !sharedStrings.ContainsKey(text)) {
// create Cell with InlineString as a child, which has Text as a child
r.Append(new OpenXmlElement[] {
new Cell(new InlineString(new Text { Text = text })) {
DataType = CellValues.InlineString,
StyleIndex = styleIndex,
CellReference = GetCellReference(iRow, (uint)iCol)
}
});
} else {
r.Append(new OpenXmlElement[] {
// create Cell with CellValue as a child, which has Text as a child
new Cell(new CellValue { Text = sharedStrings[text].ToString(CultureInfo.InvariantCulture) }) {
DataType = CellValues.SharedString,
StyleIndex = styleIndex,
CellReference = GetCellReference(iRow, (uint)iCol)
}
});
}
}
return r;
}
private static void FillSpreadsheetDocument (SpreadsheetDocument spreadsheetDocument, IList<ColumnModel> columnModels, IList<string[]> data, string sheetName) {
if (columnModels == null)
throw new ArgumentNullException("columnModels");
if (data == null)
throw new ArgumentNullException("data");
// add empty workbook and worksheet to the SpreadsheetDocument
var workbookPart = spreadsheetDocument.AddWorkbookPart();
var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
var workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
// create styles for the header and columns
workbookStylesPart.Stylesheet = new Stylesheet(
new Fonts(
// Index 0 - The default font.
new Font(
new FontSize { Val = 11 },
new Color { Rgb = new HexBinaryValue { Value = "00000000" } },
new FontName { Val = "Calibri" }
),
// Index 1 - The bold font.
new Font(
new Bold(),
new FontSize { Val = 11 },
new Color { Rgb = new HexBinaryValue { Value = "00000000" } },
new FontName { Val = "Calibri" }
)
),
new Fills(
// Index 0 - required, reserved by Excel - no pattern
new Fill(new PatternFill { PatternType = PatternValues.None }),
// Index 1 - required, reserved by Excel - fill of gray 125
new Fill(new PatternFill { PatternType = PatternValues.Gray125 }),
// Index 2 - no pattern text on gray background
new Fill(new PatternFill {
PatternType = PatternValues.Solid,
BackgroundColor = new BackgroundColor { Indexed = 64U },
ForegroundColor = new ForegroundColor { Rgb = "FFD9D9D9" }
})
),
new Borders(
// Index 0 - The default border.
new Border(
new LeftBorder(),
new RightBorder(),
new TopBorder(),
new BottomBorder(),
new DiagonalBorder()
),
// Index 1 - Applies a Left, Right, Top, Bottom border to a cell
new Border(
new LeftBorder(new Color { Auto = true }) { Style = BorderStyleValues.Thin },
new RightBorder(new Color { Auto = true }) { Style = BorderStyleValues.Thin },
new TopBorder(new Color { Auto = true }) { Style = BorderStyleValues.Thin },
new BottomBorder(new Color { Auto = true }) { Style = BorderStyleValues.Thin },
new DiagonalBorder()
)
),
new CellFormats(
// Index 0 - The default cell style. If a cell does not have a style iCol applied it will use this style combination instead
new CellFormat {
NumberFormatId = (UInt32Value)0U,
FontId = (UInt32Value)0U,
FillId = (UInt32Value)0U,
BorderId = (UInt32Value)0U
},
// Index 1 - Alignment Left, Text
new CellFormat(new Alignment { Horizontal = HorizontalAlignmentValues.Left }) {
NumberFormatId = (UInt32Value)49U, // "@" - text format - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)0U,
FillId = (UInt32Value)0U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true,
ApplyAlignment = true
},
// Index 2 - Interger Number
new CellFormat {
NumberFormatId = (UInt32Value)1U, // "0" - integer format - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)0U,
FillId = (UInt32Value)0U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true
},
// Index 3 - Interger Date
new CellFormat {
NumberFormatId = (UInt32Value)14U, // "14" - date format mm-dd-yy - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)0U,
FillId = (UInt32Value)0U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true
},
// Index 4 - Text for headers
new CellFormat(new Alignment {
Vertical = VerticalAlignmentValues.Center,
Horizontal = HorizontalAlignmentValues.Center
}) {
NumberFormatId = (UInt32Value)49U, // "@" - text format - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)1U,
FillId = (UInt32Value)2U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true,
ApplyAlignment = true
},
// Index 5 - Text for headers rotated
new CellFormat(new Alignment {
Horizontal = HorizontalAlignmentValues.Center,
TextRotation = (UInt32Value)90U
}) {
NumberFormatId = (UInt32Value)49U, // "@" - text format - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)1U,
FillId = (UInt32Value)2U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true,
ApplyAlignment = true
},
// Index 6 - Alignment Center, Text
new CellFormat(new Alignment { Horizontal = HorizontalAlignmentValues.Center }) {
NumberFormatId = (UInt32Value)49U, // "@" - text format - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)0U,
FillId = (UInt32Value)0U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true,
ApplyAlignment = true
},
// Index 7 - Alignment Right, Text
new CellFormat(new Alignment { Horizontal = HorizontalAlignmentValues.Right }) {
NumberFormatId = (UInt32Value)49U, // "@" - text format - see http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformat.aspx
FontId = (UInt32Value)0U,
FillId = (UInt32Value)0U,
BorderId = (UInt32Value)1U,
ApplyNumberFormat = true,
ApplyAlignment = true
}
)
);
workbookStylesPart.Stylesheet.Save();
// create and fill SheetData
var sheetData = new SheetData();
// first row is the header
uint iRow = 1;
sheetData.AppendChild(CreateColumnHeaderRow(iRow++, columnModels));
//iRow++; // skip one row for the filter
// first of all collect all different strings
var sst = new SharedStringTable();
var sharedStrings = new SortedDictionary<string, int>();
foreach (var dataRow in data)
for (var iCol = 0; iCol < dataRow.Length; iCol++)
if (iCol >= columnModels.Count || columnModels[iCol].Type != ExcelCellDataType.Integer) {
string text = (columnModels[iCol].Type == ExcelCellDataType.Date
? dataRow[iCol]
: ConvertDateToString(dataRow[iCol])) ?? String.Empty;
if (!String.IsNullOrEmpty(text) && !sharedStrings.ContainsKey(text)) {
sst.AppendChild(new SharedStringItem(new Text(text)));
sharedStrings.Add(text, sharedStrings.Count);
}
}
var shareStringPart = workbookPart.AddNewPart<SharedStringTablePart>();
shareStringPart.SharedStringTable = sst;
shareStringPart.SharedStringTable.Save();
foreach (var dataRow in data)
sheetData.AppendChild(CreateRow(iRow++, dataRow, columnModels, sharedStrings));
// add sheet data to Worksheet
worksheetPart.Worksheet = new Worksheet(sheetData);
worksheetPart.Worksheet.Save();
// fill workbook with the Worksheet
spreadsheetDocument.WorkbookPart.Workbook = new Workbook(
new FileVersion { ApplicationName = "Microsoft Office Excel" },
new Sheets(new Sheet {
Name = sheetName,
SheetId = (UInt32Value)1U,
Id = workbookPart.GetIdOfPart(worksheetPart) // generate the id for sheet
})
);
spreadsheetDocument.WorkbookPart.Workbook.Save();
spreadsheetDocument.Close();
}
public static void FillSpreadsheetDocument (Stream stream, IList<ColumnModel> columnModels, IList<string[]> data, string sheetName) {
using (var spreadsheetDocument = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook)) {
FillSpreadsheetDocument(spreadsheetDocument, columnModels, data, sheetName);
}
}
}
class Program {
static void Main () {
var data = new[] {
new [] {"Tom", "30", "x", null, "1974-06-16"},
new [] {"Margarita", "34", "x", "x", null},
new [] {"Bob", "7", "", "", "2005-06-26"},
new [] {"Oleg", null, "x", "x", "1964-09-11"},
new [] {"Frank", "29", "", "x", "1983-01-28"}
};
using (var stream = new FileStream("Test.xlsx", FileMode.Create)) {
ExportToExcel.FillSpreadsheetDocument(stream,
new[] {
new ColumnModel { Type = ExcelCellDataType.String, Alignment = HorizontalAlignment.Left, Header = "Name" },
new ColumnModel { Type = ExcelCellDataType.Integer, Header = "Age" },
new ColumnModel { Type = ExcelCellDataType.String, Header = "Is Married", Alignment = HorizontalAlignment.Center, IsRotatedHeader = true },
new ColumnModel { Type = ExcelCellDataType.String, Header = "Has Children", Alignment = HorizontalAlignment.Center, IsRotatedHeader = true },
new ColumnModel { Type = ExcelCellDataType.Date, Header = "Birthday", Alignment = HorizontalAlignment.Left }
},
data,
"Friends");
}
}
}
}
php + jqgrid + экспорт в excel
Хотя это решение PHP, его ядро, похоже, находится в Javascript, если это поможет.
Вы можете использовать формат Office XML (http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats). Единственным недостатком является то, что на выходе будет XML-файл, а не двоичный файл. Однако он открывается и ведет себя точно так же, как и обычный файл.xls.
То, что я делал раньше, - это перепроектировать Excel в нужном мне формате, затем сохранить его в формате.xml, открыть его в Notepad++ и выяснить заголовок, таблицу (преобразованную из сетки) и, наконец, нижний колонтитул.
Пример:
Заголовок (может быть жестко закодирован)
<?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>phpGrid.com</Author>
<Created></Created>
<LastSaved></LastSaved>
<Version></Version>
</DocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>768</WindowHeight>
<WindowWidth>1024</WindowWidth>
<WindowTopX>0</WindowTopX>
<WindowTopY>0</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom" />
<Borders/>
<Font ss:FontName="Arial" ss:Size="8" />
<Interior/>
<NumberFormat />
<Protection />
</Style>
<Style ss:ID="sHyperlink" ss:Name="Hyperlink">
<Font ss:Color="#0000FF" ss:Underline="Single" />
</Style>
<Style ss:ID="sDate">
<NumberFormat ss:Format="Short Date"/>
</Style>
<Style ss:ID="sNumber">
<NumberFormat/>
</Style>
<Style ss:ID="sHeader">
<Font ss:Family="Arial" ss:Bold="1" />
</Style>
<Style ss:ID="sDecimal">
<NumberFormat ss:Format="Fixed"/>
</Style>
</Styles><Worksheet ss:Name="Sheet1">
Тело (это таблица, преобразованная из таблицы данных. Должна быть сгенерирована динамически)
<Table ss:ExpandedColumnCount="7"
ss:ExpandedRowCount="328" x:FullColumns="1"
x:FullRows="1"><Row><Cell ss:StyleID="sHeader"><Data ss:Type="String">Order No.</Data></Cell><Cell ss:StyleID="sHeader"><Data ss:Type="String">Order Date</Data></Cell><Cell ss:StyleID="sHeader"><Data ss:Type="String">Shipped Date</Data></Cell><Cell ss:StyleID="sHeader"><Data ss:Type="String">status</Data></Cell><Cell ss:StyleID="sHeader"><Data ss:Type="String">comments</Data></Cell><Cell ss:StyleID="sHeader"><Data ss:Type="String">Customer No.</Data></Cell></Row>
<Row><Cell ss:StyleID="sNumber"><Data ss:Type="Number">0</Data></Cell><Cell><Data ss:Type="String">2010-08-20 00:00:00</Data></Cell><Cell><Data ss:Type="String"></Data></Cell><Cell><Data ss:Type="String">Open</Data></Cell><Cell><Data ss:Type="String">foo</Data></Cell><Cell ss:StyleID="sNumber"><Data ss:Type="Number">123456</Data></Cell></Row>
<Row><Cell ss:StyleID="sNumber"><Data ss:Type="Number">10100</Data></Cell><Cell><Data ss:Type="String">2003-01-06 00:00:00</Data></Cell><Cell><Data ss:Type="String">2003-01-10 00:00:00</Data></Cell><Cell><Data ss:Type="String">Shipped</Data></Cell><Cell><Data ss:Type="String">foo</Data></Cell><Cell ss:StyleID="sNumber"><Data ss:Type="Number">363</Data></Cell></Row>
<Row><Cell ss:StyleID="sNumber"><Data ss:Type="Number">10101</Data></Cell><Cell><Data ss:Type="String">2003-01-18 00:00:00</Data></Cell><Cell><Data ss:Type="String">2003-01-22 00:00:00</Data></Cell><Cell><Data ss:Type="String">Shipped</Data></Cell><Cell><Data ss:Type="String">Check on availability.</Data></Cell><Cell ss:StyleID="sNumber"><Data ss:Type="Number">128</Data></Cell></Row></Table>
Нижний колонтитул (может быть жестко закодирован)
<WorksheetOptions
xmlns="urn:schemas-microsoft-com:office:excel">
<Print>
<ValidPrinterInfo />
<HorizontalResolution>800</HorizontalResolution>
<VerticalResolution>0</VerticalResolution>
</Print>
<Selected />
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>1</ActiveRow>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>
Вы можете просто жестко закодировать XML верхнего и нижнего колонтитула, только тело будет сгенерировано динамически. Если вам нужно настроить и другие стили, необходимые. Попробуйте тот же метод "обратного инжиниринга" еще раз и выясните, что нужно добавить в XML.
Одним из преимуществ, которое я нашел таким образом, является то, что вам не нужно полагаться на API, потому что буквально все может быть объединено в строку. Он работает на разных языках программирования. Может быть не таким гибким или мощным, как API, но для сетки данных, только с таблицей, строками и столбцами, этого достаточно. По крайней мере для меня.