当前位置: 首页 > news >正文

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;
                    }
        }

 

 

转载于:https://www.cnblogs.com/Hcsdn/p/3223407.html

相关文章:

  • Delphi 数据类型列表
  • 在struts1.1框架下,利用smartupload实现文件的上传(可以是多个文件)
  • [转帖]三星F488E的JAVA安装方法
  • UICheckBox 用法解析
  • MySQL笔记系列:数据库概述
  • JOIN 和 WHERE?简单的问题也有学问。
  • 图像替换技术
  • WCF 第四章 绑定 创建一个自定义绑定
  • 健康小常识
  • 似水流年 ? Chrome调试大全
  • 关于gulp复制文件时把整个目录结构都复制的问题解决
  • java 求集合真子集_高中数学第2讲:子集与并集
  • 网线传输速度测试_如何鉴定网线好坏?怎样测网线电阻?
  • 展示 用户画像_智能时代如何做好精准营销?从用户画像智能化开始
  • centos 一键安装ftp 配置_CentOS6一键安装vsftp脚本
  • docker容器内的网络抓包
  • ES6 学习笔记(一)let,const和解构赋值
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JAVA并发编程--1.基础概念
  • js面向对象
  • js中forEach回调同异步问题
  • Laravel Mix运行时关于es2015报错解决方案
  • ng6--错误信息小结(持续更新)
  • Nodejs和JavaWeb协助开发
  • oschina
  • react 代码优化(一) ——事件处理
  • REST架构的思考
  • SpiderData 2019年2月25日 DApp数据排行榜
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 回顾2016
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 计算机在识别图像时“看到”了什么?
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 排序算法之--选择排序
  • 什么软件可以剪辑音乐?
  • 通过几道题目学习二叉搜索树
  • 一天一个设计模式之JS实现——适配器模式
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 如何正确理解,内页权重高于首页?
  • !!java web学习笔记(一到五)
  • #HarmonyOS:基础语法
  • (1)虚拟机的安装与使用,linux系统安装
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (js)循环条件满足时终止循环
  • (python)数据结构---字典
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (过滤器)Filter和(监听器)listener
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .apk文件,IIS不支持下载解决
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复