使用Open Xml为Excel 2013创buildxlsx文件

我需要创build一个Excel文件xlsx。 所以,我决定使用Open xml(Open Xml 2.0,因为我必须使用.net 3.5)。

经过一些关于打开xml的研究,我创build了这个类:

public class ExcelFileManager : FileManager { private SpreadsheetDocument _package; private Row _currentRow; private SheetData _sheetData; private int? _cellColumnN2; private int _cellColumnN1; private int _cellRow; public ExcelFileManager(string path) : base(path) { _package = SpreadsheetDocument.Create(path, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook); _cellColumnN1 = 65; _cellRow = 1; CreateSpreadSheet(); } private void CreateSpreadSheet() { var workbookPart1 = _package.AddWorkbookPart(); workbookPart1.Workbook = new Workbook(); var worksheetPart1 = workbookPart1.AddNewPart<WorksheetPart>(); worksheetPart1.Worksheet = new Worksheet(); var sheets = _package.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets()); var sheet = new Sheet() { Id = _package.WorkbookPart. GetIdOfPart(worksheetPart1), SheetId = 1, Name = "Users" }; sheets.Append(sheet); _sheetData = new SheetData(); _currentRow = new Row(); _sheetData.Append(_currentRow); worksheetPart1.Worksheet.Append(_sheetData); } public override void AddHeader(IEnumerable<string> columnsName) { if (columnsName == null || !columnsName.Any()) throw new ArgumentNullException("columnsName"); try { AddRow(columnsName.ToArray()); } catch (Exception e) { Tracing.Application.TraceError(-1, "An error occured when adding header to excel file", e); throw; } } public override void AddRow(params object[] values) { if (values == null || !values.Any()) throw new ArgumentNullException("values"); try { var listCells = new List<OpenXmlElement>(); foreach (var item in values) { listCells.Add(CreateCellRow(item)); } _currentRow.Append(listCells); AddNewRow(); } catch (Exception e) { Tracing.Application.TraceError(-1, "An error occured when adding row to excel file", e); throw; } } public override void AddCell(object value) { try { var cell = CreateCellRow(value); _currentRow.Append(cell); } catch (Exception e) { Tracing.Application.TraceError(-1, "An error occured when adding cell to excel file", e); throw; } } public override void AddNewRow() { _currentRow = new Row(); _sheetData.Append(_currentRow); IncreaseRow(); } #region Utils private Cell CreateCellRow(object value) { Tracing.Application.TraceInformation("Add value \"{0}\" in cell {1}", value, GetCellLocation()); Cell cell = new Cell(); if (value == null) { cell.CellValue = new CellValue(string.Empty); cell.DataType = CellValues.String; } else { cell.CellValue = new CellValue(value.ToString()); cell.DataType = GetCellType(value); } cell.CellReference = GetCellLocation(); IncreaseCellColumn(); return cell; } private CellValues GetCellType(object value) { CellValues type = CellValues.String; if (value.GetType() == typeof(DateTime) || value.GetType() == typeof(DateTime?)) type = CellValues.Date; if (value.GetType() == typeof(bool) || value.GetType() == typeof(bool?)) type = CellValues.Boolean; if (IsNumericType(value.GetType())) type = CellValues.Number; return type; } public bool IsNumericType(Type type) { TypeCode typeCode = Type.GetTypeCode(type); //The TypeCode of numerical types are between SByte (5) and Decimal (15). return (int)typeCode >= 5 && (int)typeCode <= 15; } private void IncreaseCellColumn() { if (_cellColumnN1 < 90) _cellColumnN1++; else { _cellColumnN1 = 65; if (!_cellColumnN2.HasValue) _cellColumnN2 = 65; else _cellColumnN2++; } } private void IncreaseRow() { _cellRow++; _cellColumnN1 = 65; _cellColumnN2 = null; } private string GetCellLocation() { Char? c1 = null; if (_cellColumnN2.HasValue) c1 = (char)_cellColumnN2; Char c2 = (char)_cellColumnN1; return string.Format("{0}{1}{2}", c1, c2, _cellRow); } #endregion #region IDisposable public override void Dispose() { if (_package != null) { _package.WorkbookPart.Workbook.Save(); _package.Close(); } } #endregion } 

当我使用这个类创build一个excel文件时,会显示一条错误消息:“我们在内容中发现了一个错误…”Excel修复了这个文件,并且它变成了可打开的。 为什么我在Excel中有这个错误?

我在xlsx文件中包含的xml文件sheet.xml中看了一下,几乎没有什么区别:

生成的文件:

 <x:worksheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <x:sheetData> <x:row> <x:cr="A1" t="str"> <x:v>a string</x:v> </x:c> <x:cr="B1" t="str"> <x:v>another string</x:v> </x:c> </x:row> ... </x:sheetData> </x:worksheet> 

修复文件:

 <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"> <dimension ref="A1:S12"/> <sheetViews> <sheetView tabSelected="1" workbookViewId="0"> <selection activeCell="I11" sqref="I11"/> </sheetView> </sheetViews> <sheetFormatPr baseColWidth="10" defaultRowHeight="15" x14ac:dyDescent="0.25"/> <sheetData> <row r="1" spans="1:19" x14ac:dyDescent="0.25"> <cr="A1" t="s"> <v>0</v> </c> <cr="B1" t="s"> <v>1</v> </c> <cr="C1" t="s"> <v>2</v> </c> </row> ... </sheetData> <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/> </worksheet> 

我试图改变命名空间,但它没有工作。 我知道在第二个XML中使用共享string,但我不认为这是问题。 ^^我不关心风格,如页边距,字体,…(可能是自动调整列的宽度将是有用的^^)

我只想要一个格式良好的xlsx文件。

我的代码中是否有错误或遗漏?

对不起,我的英语的方式'^^

谢谢。

date被存储为具有types编号的数字,但具有应用于它们的样式。 布尔值也被存储为数字,但types为布尔值。

 private Cell CreateCellRow(object value) { Cell cell = new Cell(); cell.CellReference = GetCellLocation(); IncreaseCellColumn(); if (value == null) { cell.DataType = CellValues.InlineString; cell.InlineString = new InlineString { Text = new Text("") }; return cell; } switch (Type.GetTypeCode(value.GetType())) { case TypeCode.DateTime: cell.StyleIndex = 1; cell.CellValue = new CellValue(((DateTime)value).ToOADate().ToString(CultureInfo.InvariantCulture)); break; case TypeCode.String: cell.DataType = CellValues.InlineString; cell.InlineString = new InlineString {Text = new Text((string) value)}; break; case TypeCode.Boolean: cell.DataType = CellValues.Boolean; cell.CellValue = new CellValue((bool)value ? "1" : "0"); break; case TypeCode.Byte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Single: cell.CellValue = new CellValue(((IFormattable)value).ToString(null, CultureInfo.InvariantCulture)); break; default: throw new Exception("Unrecognized type: " + value.GetType().FullName); } return cell; } 

创build所需的样式(从另一个答案中删除):

 var stylesPart = workbookPart.AddNewPart<WorkbookStylesPart>(); stylesPart.Stylesheet = CreateStylesheet(); 
 private Stylesheet CreateStylesheet() { var stylesheet = new Stylesheet(); // Default Font var fonts = new Fonts() { Count = 1, KnownFonts = BooleanValue.FromBoolean(true) }; var font = new Font { FontSize = new FontSize() { Val = 11 }, FontName = new FontName() { Val = "Calibri" }, FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 }, FontScheme = new FontScheme() { Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor) } }; fonts.Append(font); stylesheet.Append(fonts); // Default Fill var fills = new Fills() { Count = 1 }; var fill = new Fill(); fill.PatternFill = new PatternFill() { PatternType = new EnumValue<PatternValues>(PatternValues.None) }; fills.Append(fill); stylesheet.Append(fills); // Default Border var borders = new Borders() { Count = 1 }; var border = new Border { LeftBorder = new LeftBorder(), RightBorder = new RightBorder(), TopBorder = new TopBorder(), BottomBorder = new BottomBorder(), DiagonalBorder = new DiagonalBorder() }; borders.Append(border); stylesheet.Append(borders); // Default cell format and a date cell format var cellFormats = new CellFormats() { Count = 2 }; var cellFormatDefault = new CellFormat { NumberFormatId = 0, FormatId = 0, FontId = 0, BorderId = 0, FillId = 0 }; cellFormats.Append(cellFormatDefault); var cellFormatDate = new CellFormat { NumberFormatId = 22, FormatId = 0, FontId = 0, BorderId = 0, FillId = 0, ApplyNumberFormat = BooleanValue.FromBoolean(true) }; cellFormats.Append(cellFormatDate); stylesheet.Append(cellFormats); return stylesheet; }