Open XML SDK Quick Guide - Otaku-Projects/ReportEngine GitHub Wiki

Official Documentation

Welcome to the Open XML SDK for Office
https://learn.microsoft.com/en-us/office/open-xml/open-xml-sdk

>Welcome to the Open XML SDK for Office
>Spreadsheets
>Structure of a SpreadsheetML document
>Worksheet Class
https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.worksheet?view=openxml-2.8.1&redirectedfrom=MSDN

(Microsoft always provides API documentation only, lack of sample codes and complete workflow tutorial, or is hard to find, very unfriendly.)

Generate Sample Code

Prepare a simple Excel/Word/Powerpoint, I created an Excel that contains a table with filter, border, and fields of numeric, date, text value.

  1. Open Open XML SDK 2.5 Productivity Tool
  2. Click Open File..., select the target excel then Open
  3. Click Reflect Code
  4. Copy the generated cs code to your Visual Studio

image

Sample Code and Explanation

// ...

        // Adds child parts and generates content of the specified part.
        private void CreateParts(SpreadsheetDocument document)
        {
            ExtendedFilePropertiesPart extendedFilePropertiesPart1 = document.AddNewPart<ExtendedFilePropertiesPart>("rId3");
            GenerateExtendedFilePropertiesPart1Content(extendedFilePropertiesPart1);

            WorkbookPart workbookPart1 = document.AddWorkbookPart();
            GenerateWorkbookPart1Content(workbookPart1);

            WorkbookStylesPart workbookStylesPart1 = workbookPart1.AddNewPart<WorkbookStylesPart>("rId3");
            GenerateWorkbookStylesPart1Content(workbookStylesPart1);

            ThemePart themePart1 = workbookPart1.AddNewPart<ThemePart>("rId2");
            GenerateThemePart1Content(themePart1);

            WorksheetPart worksheetPart1 = workbookPart1.AddNewPart<WorksheetPart>("rId1");
            GenerateWorksheetPart1Content(worksheetPart1);

            SpreadsheetPrinterSettingsPart spreadsheetPrinterSettingsPart1 = worksheetPart1.AddNewPart<SpreadsheetPrinterSettingsPart>("rId1");
            GenerateSpreadsheetPrinterSettingsPart1Content(spreadsheetPrinterSettingsPart1);

            SharedStringTablePart sharedStringTablePart1 = workbookPart1.AddNewPart<SharedStringTablePart>("rId4");
            GenerateSharedStringTablePart1Content(sharedStringTablePart1);

            SetPackageProperties(document);
        }
// ...

GenerateWorkbookPart1Content()

  • workbook
  • worksheet(spreadsheet)

GenerateWorkbookStylesPart1Content()

  • Sheet style
  • Numbering format (date/time/datetime/numeric format...)
  • Font (size, font style, color...)
  • Fill (cell background color)
  • Border
  • Cell Style Format (a combination of font master, fill master, border master)
  • Cell formats (associated with the above numbering format master, font master, fill master, border master, cell style format master, ApplyBorder flag, ApplyNumberFormat flag, ApplyAlignment flag, Alignment)
  • Alignment
            Borders borders1 = new Borders(){ Count = (UInt32Value)2U };
            Border border1 = new Border();
//...

            Border border2 = new Border();
//...
            borders1.Append(border1); // index = 0
            borders1.Append(border2); // index = 1

            #region cell format: numeric, date, time, datetime, string
            NumberingFormats numberingFormats1 = new NumberingFormats() { Count = (UInt32Value)1U };
            NumberingFormat numberingFormat1 = new NumberingFormat() { NumberFormatId = (UInt32Value)164U, FormatCode = "\"HK$\"#,##0.00" };
            NumberingFormat numberingFormat2 = new NumberingFormat() { NumberFormatId = (UInt32Value)9U, FormatCode = "0" };
            NumberingFormat numberingFormat3 = new NumberingFormat() { NumberFormatId = (UInt32Value)165U, FormatCode = "@" };

            numberingFormats1.Append(numberingFormat1);
            numberingFormats1.Append(numberingFormat2);
            numberingFormats1.Append(numberingFormat3);
            #endregion

            CellFormats cellFormats1 = new CellFormats(){ Count = (UInt32Value)6U };

            CellFormat cellFormat7 = new CellFormat(){ NumberFormatId = (UInt32Value)0U, FontId = (UInt32Value)0U, FillId = (UInt32Value)0U, BorderId = (UInt32Value)1U, FormatId = (UInt32Value)0U, ApplyBorder = true, ApplyAlignment = true };
            Alignment alignment2 = new Alignment(){ Horizontal = HorizontalAlignmentValues.Center };

            cellFormat7.Append(alignment2);

            cellFormats1.Append(cellFormat2); // index = 0
            cellFormats1.Append(cellFormat3); // index = 1
            cellFormats1.Append(cellFormat4); // index = 2
            cellFormats1.Append(cellFormat5); // index = 3
            cellFormats1.Append(cellFormat6); // index = 4
            cellFormats1.Append(cellFormat7); // index = 5

The binding ID is an integer number, and the created master is associated with an ascending integer number.
for BorderId = (UInt32Value)1U, which means using border2.

GenerateThemePart1Content()
Excel color theme

GenerateWorksheetPart1Content()
generate content, column style, row style, cell value and style, filter, merge cells

            Cell cell12 = new Cell(){ CellReference = "E5", StyleIndex = (UInt32Value)5U, DataType = CellValues.SharedString };
            CellValue cellValue7 = new CellValue();
            cellValue7.Text = "2";
  • cell12 using index 2 of Shared string content which "HKID no."
  • StyleIndex = (UInt32Value)5U means cellFormat7 which is associated with specified border, alignment
  • NumberFormatId = (UInt32Value)0U control the cell format, open XML 2.0/3.0 excel predefined NumberFormatId from 0 ~ 49, I custom made 164, 165

for using 164 Hong Kong Dollar format ""HK$"#,##0.00", change the NumberFormatId to 164 in CellFormat cellFormat7 = new CellFormat(){ NumberFormatId = (UInt32Value)0U,

or create a new CellFormat, set NumberFormatId as 164 on initial, add to cellFormats1, update the Count of cellFormats1, then update the Cell's StyleIndex

In conclusion, to locate a cell format, from Cell > Cell's StyleIndex > CellFormat (Refer to CellFormats appended index) > NumberFormatId (Refer to NumberingFormat's NumberingFormatId appended in NumberingFormats)

Microsoft is suck, how fraking complicated

https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.numberingformat?view=openxml-3.0.1

GenerateSpreadsheetPrinterSettingsPart1Content()
Print area settings? (not sure)

GenerateSharedStringTablePart1Content()

  • Shared Text the created shared text could be used by cells in multiple worksheets
            SharedStringTable sharedStringTable1 = new SharedStringTable(){ Count = (UInt32Value)13U, UniqueCount = (UInt32Value)13U };

            SharedStringItem sharedStringItem1 = new SharedStringItem();
            Text text1 = new Text();
            text1.Text = "No.";

            sharedStringItem1.Append(text1);

            SharedStringItem sharedStringItem2 = new SharedStringItem();
            Text text2 = new Text();
            text2.Text = "Name of Patient";

            sharedStringItem2.Append(text2);

            SharedStringItem sharedStringItem3 = new SharedStringItem();
            Text text3 = new Text();
            text3.Text = "HKID no.";

            sharedStringItem3.Append(text3);

//...

SetPackageProperties()

  • Creator
  • Created
  • Modified
  • LastModifiedBy

Snippet - Pivot Table Filter

For the code with filter

// Generates content of pivotTablePart1.
        private void GeneratePivotTablePart1Content(PivotTablePart pivotTablePart1)
...
            Location location1 = new Location(){ Reference = "A5:B9", FirstHeaderRow = (UInt32Value)1U, FirstDataRow = (UInt32Value)1U, FirstDataColumn = (UInt32Value)1U, RowPageCount = (UInt32Value)1U, ColumnsPerPage = (UInt32Value)1U };
...

            PivotField pivotField10 = new PivotField(){ Axis = PivotTableAxisValues.AxisPage, ShowAll = false };
...            
            PageFields pageFields1 = new PageFields(){ Count = (UInt32Value)1U };
            PageField pageField1 = new PageField(){ Field = 9, Hierarchy = -1 };
            pageFields1.Append(pageField1);
...
            pivotTableDefinition1.Append(pageFields1);

For the code without filter

// Generates content of pivotTablePart1.
        private void GeneratePivotTablePart1Content(PivotTablePart pivotTablePart1)
...
            Location location1 = new Location(){ Reference = "A5:B9", FirstHeaderRow = (UInt32Value)1U, FirstDataRow = (UInt32Value)1U, FirstDataColumn = (UInt32Value)1U };
...
            PivotField pivotField10 = new PivotField(){ ShowAll = false };
...
// removed PageFields pageFields1
...
// removed pivotTableDefinition1.Append(pageFields1);

I put Pivot on "sheet2", for the field = 9, it refers to the column J (Zero-based index) at "sheet1" it was defined under GeneratePivotTableCacheDefinitionPart1Content()

WorksheetSource worksheetSource1 = new WorksheetSource(){ Reference = "A1:K7", Sheet = "Sheet1" };

Snippet - Remove column in sheet 1, Pivot Table on sheet 2

Prepare an Excel,

  1. Remove all the raw data except one row remaining, refresh the Pivot Table
  2. Right click on the Pivot > PivotTable Options > Data Tab > Set None for "Number of items to retain per field", click save
  3. back to the raw data sheet, confirm only one row of raw data remaining, click save again Both would reduce the data volume and remove the pivot table cache (which means the shared string in code)
    Then use the tool to compare two excel reflect code, listed the difference below
        // Generates content of workbookPart1.
        private void GenerateWorkbookPart1Content(WorkbookPart workbookPart1)
...
            DefinedNames definedNames1 = new DefinedNames();
            DefinedName definedName1 = new DefinedName(){ Name = "_xlnm._FilterDatabase", LocalSheetId = (UInt32Value)1U, Hidden = true };
            definedName1.Text = "Sheet1!$A$1:$K$2";
...
            PivotCaches pivotCaches1 = new PivotCaches();
            PivotCache pivotCache1 = new PivotCache(){ CacheId = (UInt32Value)12U, Id = "rId3" };
...
        // Generates content of pivotTableCacheDefinitionPart1.
        private void GeneratePivotTableCacheDefinitionPart1Content(PivotTableCacheDefinitionPart pivotTableCacheDefinitionPart1)
...
            WorksheetSource worksheetSource1 = new WorksheetSource(){ Reference = "A1:K2", Sheet = "Sheet1" };
...
            CacheFields cacheFields1 = new CacheFields(){ Count = (UInt32Value)12U };
...
// one of the cache field was removed
            cacheFields1.Append(cacheField8);
        // Generates content of pivotTableCacheRecordsPart1.
        private void GeneratePivotTableCacheRecordsPart1Content(PivotTableCacheRecordsPart pivotTableCacheRecordsPart1)
// I removed the cache to save efforts for making cache in coding, remember to enable refresh on load
            // remove pivot cache
            //pivotTableCacheRecordsPart1.PivotCacheRecords = pivotCacheRecords1;
// Generates content of worksheetPart1.
        private void GenerateWorksheetPart1Content(WorksheetPart worksheetPart1)
...
            SheetDimension sheetDimension1 = new SheetDimension(){ Reference = "A1:L2" };
...
            SheetView sheetView1 = new SheetView(){ TopLeftCell = "B1", WorkbookViewId = (UInt32Value)0U };
            Selection selection1 = new Selection(){ ActiveCell = "I2", SequenceOfReferences = new ListValue<StringValue>() { InnerText = "I2" } };
...
// remember to remove a column in columns1
            columns1.Append(column9);
// remember to remove a column when printing body row
            row1.Append(cell9);
...
// update raw data sheet filter if exists
AutoFilter autoFilter1 = new AutoFilter(){ Reference = "A1:L99986" };
...
// I am not sure is sheetDimension1 required update necessary, I comment it, the excel still generate successfully
// worksheet1.Append(sheetDimension1);
        // Generates content of pivotTablePart1.
        private void GeneratePivotTablePart1Content(PivotTablePart pivotTablePart1)
...
            PivotFields pivotFields1 = new PivotFields(){ Count = (UInt32Value)12U };
...
// remove one of pivotFields
pivotFields1.Append(pivotField9);
...
            PageFields pageFields1 = new PageFields(){ Count = (UInt32Value)1U };
            PageField pageField1 = new PageField(){ Field = 8, Hierarchy = -1 };

            pageFields1.Append(pageField1);
...
            DataFields dataFields1 = new DataFields(){ Count = (UInt32Value)1U };
            DataField dataField1 = new DataField(){ Name = "No. of service users eligible for Annual Grant", Field = (UInt32Value)9U, BaseField = 6, BaseItem = (UInt32Value)0U };

Snippet - Enable Pivot Table Refresh on load

the result same as

  1. Right click on Pivot > PivotTable Options > Data Tab
  2. Check "Refresh data when opening the file"
        // Generates content of pivotTableCacheDefinitionPart1.
        private void GeneratePivotTableCacheDefinitionPart1Content(PivotTableCacheDefinitionPart pivotTableCacheDefinitionPart1, AnnualGrantPatientSearchCriteria criteria, int dataLength = 1)
...
        pivotCacheDefinition1.RefreshOnLoad = true;

How to Create Custom Excel

Add, and modify cell, styles in GenerateWorkbookStylesPart1Content()

For table body, create a loop in GenerateWorksheetPart1Content() Create row in loop, add row by something like sheetData1.Append(row18); For the cell not using SharedString, assign the value to Text property

            // Total Amount Reference = "E18",
            Cell cell171 = new Cell() { StyleIndex = (UInt32Value)48U };
            cell171.DataType = CellValues.Number;
            CellValue cellValue47 = new CellValue();
            cellValue47.Text = (sbd.returnValueToString(Convert.ToDecimal(dataList.Sum(x => x.APP_CLAIM_AMT))));
            cell171.Append(cellValue47);
//...
            row17.Append(cell170);
            row17.Append(cell171);
            row17.Append(cell172);
//...

How to Create Custom Word

Free e-Book - Create New Word Document
https://riptutorial.com/Download/openxml.pdf

⚠️ **GitHub.com Fallback** ⚠️