OpenXML电子表格中的单元格样式(SpreadsheetML)
我已经使用OpenXML SDK在C#中生成了一个.xlsx电子表格,但不知道如何获取单元格样式。 我一直在研究由Excel生成的文件,并不能完全弄清楚它是如何完成的。
现在,我创build一个填充,创build一个指向填充的CellFormat
,创build一个CellFormat
索引的CellStyleFormat
,然后创build一个CellStyle
的CellFormat
。
以下是我用来生成文档的代码:
Console.WriteLine("Creating document"); using (var spreadsheet = SpreadsheetDocument.Create("output.xlsx", SpreadsheetDocumentType.Workbook)) { Console.WriteLine("Creating workbook"); spreadsheet.AddWorkbookPart(); spreadsheet.WorkbookPart.Workbook = new Workbook(); Console.WriteLine("Creating worksheet"); var wsPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>(); wsPart.Worksheet = new Worksheet(); var stylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>(); stylesPart.Stylesheet = new Stylesheet(); stylesPart.Stylesheet.Fills = new Fills(); // create a solid red fill var solidRed = new PatternFill() { PatternType = PatternValues.Solid }; solidRed.AppendChild(new BackgroundColor { Rgb = HexBinaryValue.FromString("FF00FF00") }); stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill() { PatternType = PatternValues.None } }); stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = solidRed }); stylesPart.Stylesheet.CellStyleFormats = new CellStyleFormats(); stylesPart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat { FillId = 0, ApplyFill = false }); stylesPart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat { FillId = 1, ApplyFill = true }); stylesPart.Stylesheet.CellFormats = new CellFormats(); stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 0 }); stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 1 }); stylesPart.Stylesheet.CellStyles = new CellStyles(); stylesPart.Stylesheet.CellStyles.AppendChild(new CellStyle { Name = "None", FormatId = 0 }); stylesPart.Stylesheet.CellStyles.AppendChild(new CellStyle { Name = "Solid Red", FormatId = 1 }); stylesPart.Stylesheet.Save(); Console.WriteLine("Creating sheet data"); var sheetData = wsPart.Worksheet.AppendChild(new SheetData()); Console.WriteLine("Adding rows / cells..."); var row = sheetData.AppendChild(new Row()); row.AppendChild(new Cell() { CellValue = new CellValue("This"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("is"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("a"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("test."), DataType = CellValues.String }); sheetData.AppendChild(new Row()); row = sheetData.AppendChild(new Row()); row.AppendChild(new Cell() { CellValue = new CellValue("Value:"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("123"), DataType = CellValues.Number }); row.AppendChild(new Cell() { CellValue = new CellValue("Formula:"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellFormula = new CellFormula("B3"), StyleIndex = 1 }); // Console.WriteLine("Saving worksheet"); wsPart.Worksheet.Save(); Console.WriteLine("Creating sheet list"); var sheets = spreadsheet.WorkbookPart.Workbook.AppendChild(new Sheets()); sheets.AppendChild(new Sheet() { Id = spreadsheet.WorkbookPart.GetIdOfPart(wsPart), SheetId = 1, Name = "Test" }); Console.WriteLine("Saving workbook"); spreadsheet.WorkbookPart.Workbook.Save(); Console.WriteLine("Done."); }
这是生成的XML:
workbook.xml
<?xml version="1.0" encoding="utf-8"?> <x:workbook xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <x:sheets> <x:sheet name="Test" sheetId="1" r:id="Rbad86b8c80844a16" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" /> </x:sheets> </x:workbook>
styles.xml
<?xml version="1.0" encoding="utf-8"?> <x:styleSheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <x:fills> <x:fill> <x:patternFill patternType="none" /> </x:fill> <x:fill> <x:patternFill patternType="solid"> <x:bgColor rgb="FF00FF00" /> </x:patternFill> </x:fill> </x:fills> <x:cellStyleXfs> <x:xf fillId="0" applyFill="0" /> <x:xf fillId="1" applyFill="1" /> </x:cellStyleXfs> <x:cellXfs> <x:xf xfId="0" /> <x:xf xfId="1" /> </x:cellXfs> <x:cellStyles> <x:cellStyle name="None" xfId="0" /> <x:cellStyle name="Solid Red" xfId="1" /> </x:cellStyles> </x:styleSheet>
工作表/ sheet.xml
<?xml version="1.0" encoding="utf-8"?> <x:worksheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <x:sheetData> <x:row> <x:ct="str"><x:v>This</x:v></x:c> <x:ct="str"><x:v>is</x:v></x:c> <x:ct="str"><x:v>a</x:v></x:c> <x:ct="str"><x:v>test.</x:v></x:c> </x:row> <x:row /> <x:row> <x:ct="str"><x:v>Value:</x:v></x:c> <x:ct="n"><x:v>123</x:v></x:c> <x:ct="str"><x:v>Formula:</x:v></x:c> <x:cs="1"><x:f>B3</x:f></x:c> </x:row> </x:sheetData> </x:worksheet>
最后一行的最后一个单元格是我试图添加样式的地方。
当我通过OpenXML SDK生产力工具运行它时,所有的validation都正确,但是当我尝试在Excel中打开文件时,出现以下错误:
修复logging:从/xl/styles.xml部分格式(样式)
电子表格然后显示,但填充不适用。
任何想法如何去解决这个问题?
对,经过大量的实验,我设法弄清楚了这一点。
事实certificate,excel保留正常单元格的样式0和1和“Gray125”模式填充分别。 上面的大部分代码都可以被删除,因为我们只需要一个CellFormat
。
工作代码:
Console.WriteLine("Creating document"); using (var spreadsheet = SpreadsheetDocument.Create("output.xlsx", SpreadsheetDocumentType.Workbook)) { Console.WriteLine("Creating workbook"); spreadsheet.AddWorkbookPart(); spreadsheet.WorkbookPart.Workbook = new Workbook(); Console.WriteLine("Creating worksheet"); var wsPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>(); wsPart.Worksheet = new Worksheet(); var stylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>(); stylesPart.Stylesheet = new Stylesheet(); Console.WriteLine("Creating styles"); // blank font list stylesPart.Stylesheet.Fonts = new Fonts(); stylesPart.Stylesheet.Fonts.Count = 1; stylesPart.Stylesheet.Fonts.AppendChild(new Font()); // create fills stylesPart.Stylesheet.Fills = new Fills(); // create a solid red fill var solidRed = new PatternFill() { PatternType = PatternValues.Solid }; solidRed.ForegroundColor = new ForegroundColor { Rgb = HexBinaryValue.FromString("FFFF0000") }; // red fill solidRed.BackgroundColor = new BackgroundColor { Indexed = 64 }; stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill { PatternType = PatternValues.None } }); // required, reserved by Excel stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill { PatternType = PatternValues.Gray125 } }); // required, reserved by Excel stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = solidRed }); stylesPart.Stylesheet.Fills.Count = 3; // blank border list stylesPart.Stylesheet.Borders = new Borders(); stylesPart.Stylesheet.Borders.Count = 1; stylesPart.Stylesheet.Borders.AppendChild(new Border()); // blank cell format list stylesPart.Stylesheet.CellStyleFormats = new CellStyleFormats(); stylesPart.Stylesheet.CellStyleFormats.Count = 1; stylesPart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat()); // cell format list stylesPart.Stylesheet.CellFormats = new CellFormats(); // empty one for index 0, seems to be required stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()); // cell format references style format 0, font 0, border 0, fill 2 and applies the fill stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 0, FontId = 0, BorderId = 0, FillId = 2, ApplyFill = true }).AppendChild(new Alignment { Horizontal = HorizontalAlignmentValues.Center }); stylesPart.Stylesheet.CellFormats.Count = 2; stylesPart.Stylesheet.Save(); Console.WriteLine("Creating sheet data"); var sheetData = wsPart.Worksheet.AppendChild(new SheetData()); Console.WriteLine("Adding rows / cells..."); var row = sheetData.AppendChild(new Row()); row.AppendChild(new Cell() { CellValue = new CellValue("This"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("is"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("a"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("test."), DataType = CellValues.String }); sheetData.AppendChild(new Row()); row = sheetData.AppendChild(new Row()); row.AppendChild(new Cell() { CellValue = new CellValue("Value:"), DataType = CellValues.String }); row.AppendChild(new Cell() { CellValue = new CellValue("123"), DataType = CellValues.Number }); row.AppendChild(new Cell() { CellValue = new CellValue("Formula:"), DataType = CellValues.String }); // style index = 1, ie point at our fill format row.AppendChild(new Cell() { CellFormula = new CellFormula("B3"), DataType = CellValues.Number, StyleIndex = 1 }); Console.WriteLine("Saving worksheet"); wsPart.Worksheet.Save(); Console.WriteLine("Creating sheet list"); var sheets = spreadsheet.WorkbookPart.Workbook.AppendChild(new Sheets()); sheets.AppendChild(new Sheet() { Id = spreadsheet.WorkbookPart.GetIdOfPart(wsPart), SheetId = 1, Name = "Test" }); Console.WriteLine("Saving workbook"); spreadsheet.WorkbookPart.Workbook.Save(); Console.WriteLine("Done."); }
一些忠告:
如果你想避免这种疯狂,使用ClosedXML。
如果你正在做这种工作,我不能推荐ClosedXML 。 OpenXML API和格式本身就是非常繁琐的工作,有各种无证件的情况。 ClosedXML为你做了很多工作。 他们也很擅长迅速修复错误。
更通用的答案,我在testing后发现,所以没有文件指出。
一旦在样式表中设置了CellFormats
集合,Excel就会对其进行更深入的validation。
CellFormats
不能为空,它必须至less有一个CellFormat
。
一旦添加了一个CellFormat
,如果Fills
, Fonts
或Borders
集合是空的,Excel将会投诉。
第一个Font
用作整个工作簿的默认值,也是Excel中的列/行标题。
Excel将忽略第一个CellFormat
,所以只需添加一个空的。
如果你需要一个Border
或Fill
你的格式,Excel也将忽略第一个Border
和Fill
,所以也可以在Borders
和Fills
添加空的Borders
作为第一个孩子。
最后,从第二个CellFormat
( s = "1"
),你很好。
在Excel 2010中testing。