Open xml 操作Excel 透視表(Pivot table)-- 實現Excel多語言報表


我的一個ERP項目中,客戶希望使用Excel Pivot table 做分析報表。 ERP 從數據庫中讀出數據,導出到Excel中的數據源表(統一命名為Data),刷新Pivot table!

客戶還希望對Excel報表提供多語言支持, 根據用戶的語言生成不同版本的Excel文件。

經過不斷嘗試,終於成功完成該任務, 本篇簡要描述這個任務涉及到的知識點。

把一個包含透視表及透視圖的Excel .xlsx文件重命名為.zip 文件,然后解壓縮到某個文件夾下,就可以看到Excel是如何定義透視表及透視圖了, 如下圖所示,pivotTables 定義了透視表中行、列及數據字段等, PivotCache 中則定義了Pivot table 的數據源、字段匹配,以及緩存了上一次打開的數據

                       

                    (Excel文件結構)

 

                       (pivotTables\pivotTable1.xml截圖)

    (pivotCache\pivotCacheDefinition1.xml 截圖)

 

根據以上描述, 在導入數據后. 還需要完成以下步驟:

  1. 重新設置透視表 的數據源到數據區域.

重新設置Pivot table 數據源的代碼如下:    

 1         //其中sheetName為作為數據源的工作表名,lastReference為數據源中最后一個單元格的引用名,比如最后一列為AG,共10行則為AG10
 2     public static void SetPivotSource(WorkbookPart wbPart, string sheetName, string lastReference)
 3         {
 4             var pivottableCashes = wbPart.PivotTableCacheDefinitionParts;
 5             foreach (PivotTableCacheDefinitionPart pivottablecachePart in pivottableCashes)
 6             {
 7                 pivottablecachePart.PivotCacheDefinition.CacheSource.RemoveAllChildren();
 8 //設置Pivot tabla的數據源為A1:lastReference
 9                 pivottablecachePart.PivotCacheDefinition.CacheSource.Append(new WorksheetSource() {
10                     Sheet = sheetName, Reference = new StringValue("A1:" + lastReference) });
11             }
12         }

 

//假設Data表格中的最后一列的Reference為AG,總共有100行(加上列頭行共101行),則導入數據后調用 
using (SpreadsheetDocument document = SpreadsheetDocument.Open(rawFileName, true))

            {

                WorkbookPart wbPart = document.WorkbookPart;

                                SetPivotSource(wbPart,"data","AG101");

                    }

 

2.  翻譯Excel 數據源表字段名

也就是翻譯及修改Data表格中第一行的單元格內容

 

  public static void UpdateCellValue(WorkbookPart wbPart, Cell theCell,string newValue)
        {
            string value = theCell.InnerText;
            if (theCell.DataType != null)
            {
                switch (theCell.DataType.Value)
                {
                    case CellValues.SharedString:
                        var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
                        if (stringTable != null)
                        {
                            var ele = stringTable.SharedStringTable.ElementAt(int.Parse(value));
                            ele.RemoveAllChildren();
                            ele.Append(new DocumentFormat.OpenXml.Spreadsheet.Text(newValue));
                        }
                        break;

                    case CellValues.Boolean:
                        if (string.Compare(value,"FALSE",true) ==0)
                        {
                            theCell.InnerXml = "1";
                        }
                        else
                        {
                            theCell.InnerXml = "0";
                        }
                        break;
                    default:
                        theCell.InnerXml = newValue;
                        break;
                }
            }
        }

   using (SpreadsheetDocument document = SpreadsheetDocument.Open(rawFileName, true))
            {
                WorkbookPart wbPart = document.WorkbookPart;
                
                var dataSheet = wbPart.Workbook.Descendants<Sheet>().FirstOrDefault(c => string.Compare(c.Name, "Data",true)==0);
                WorksheetPart worksheetPart = (WorksheetPart)wbPart.GetPartById(dataSheet.Id);
                var headerRow = worksheetPart.Worksheet.GetFirstChild<SheetData>().Elements<Row>().
                           FirstOrDefault(c => c.RowIndex == 1);
                var cells = headerRow.Elements<Cell>().ToList();
                foreach (var cell in cells)
                {
                    var rawText = ExcelHelper.GetCellValue(wbPart, cell);
                    ExcelHelper.UpdateCellValue(wbPart, cell, _translator.Translate(rawText));
                    //cell.CellValue = new CellValue(_translator.Translate(rawText));
                    //cell.DataType = new EnumValue<CellValues>(CellValues.String);
                }
                worksheetPart.Worksheet.Save();
    }

 

3.  翻譯pivotCacheDefinition緩存區的字段定義。

 using (SpreadsheetDocument document = SpreadsheetDocument.Open(rawFileName, true))
            {
                WorkbookPart wbPart = document.WorkbookPart;
            var pivottableCashes = wbPart.PivotTableCacheDefinitionParts;
                foreach (PivotTableCacheDefinitionPart pivottablecachePart in pivottableCashes)
                {
                    pivottablecachePart.PivotCacheDefinition.RefreshOnLoad = true;
                    var pivotCacheFields = pivottablecachePart.PivotCacheDefinition.CacheFields;
                    foreach (OpenXmlElement pivotCacheField in pivotCacheFields)
                    {
                        OpenXmlAttribute nameEle = pivotCacheField.GetAttribute("name", "");
                        nameEle.Value = _translator.Translate(nameEle.Value);
                        pivotCacheField.SetAttribute(nameEle);
                    }   
                }
    }

 

4.  翻譯Pivot Table 透視表定義區域的數據字段名,以及圖表區的數據源表名

 

 //sheet為Sheet類型對象
            oxPart = wbPart.GetPartById(sheet.Id);
                    //Translate Pivot table data(numeric) field defination, such as "Sum of [Vat...]"
                    if (oxPart.ContentType.Contains("worksheet"))
                    {
                        wsP = (WorksheetPart)oxPart;
                        tbDefParts = wsP.PivotTableParts;
                        foreach (PivotTablePart ptPart in tbDefParts)
                        {
                            dataFileds = ptPart.PivotTableDefinition.DataFields;
                            foreach (DataField df in dataFileds)
                            {
                                if (df.Name.Value.StartsWith(SUM_OF))
                                {
                                    df.Name = new StringValue(_translator.Translate(SUM_OF) + " " +
                                        _translator.Translate(df.Name.Value.Replace(SUM_OF, "").Trim()));
                                }
                            }
                        }
                    }

 var index =  rawFileName.LastIndexOf(@"\");
                var filename = rawFileName.Substring(index+1);
                foreach(ChartsheetPart cspart in wbPart.ChartsheetParts)
                {
                    var chartparts = cspart.DrawingsPart.ChartParts ;
                    foreach(ChartPart cp in chartparts)
                    {
                        PivotSource pivotSource =  cp.RootElement.OfType<PivotSource>().First();
                        string originalName = pivotSource.PivotTableName.InnerText;
                        Regex reg = new Regex(@"^[[]([^]]+)[]]([^!]+)!(.*)$");
                        var matches = reg.Matches(originalName);
                        if (matches.Count > 0 && matches[0].Groups.Count >3)
                        {
                            string newName = string.Format("[{0}]{1}!{2}", filename,
                                _translator.Translate(matches[0].Groups[2].Value), matches[0].Groups[3].Value);
                            pivotSource.PivotTableName = new PivotTableName(newName);
                        }
                    }

 

5. 翻譯表格名, 需要翻譯所有除了Data表外的工作表名。

  foreach (Sheet sheet in sheets)
                {
                    if (string.Compare(sheet.Name, "data", true) != 0)
                    {
                        var translatedName = _translator.Translate(sheet.Name);
                        if (!string.IsNullOrEmpty(translatedName) && translatedName.Length > 30)
                        {
                            translatedName = translatedName.Substring(0, 30);
                        }
                        sheet.Name = translatedName;
                    }
        }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM