MaltReport2:基于 OpenDocument-OpenOfficeXML 的开源报表引擎

来源:互联网 发布:油汀电热膜哪个好 知乎 编辑:程序博客网 时间:2024/04/30 14:49

MaltReport 是我几年前写的开源单据、报表引擎,最近进行了较大的更新,尤其是几年来在生产项目中应用取得了非常好的效果,特别写篇介绍文字给大家分享一下。

首先先介绍几个名词:

  • OpenDocument:国际标准文档格式,开源办公软件 OpenOffice.org/LibreOffice 的 ODT/ODS 即为 OpenDocument 格式。
  • OfficeOpenXML:同样是国际标准文档格式,由 Microsoft 定义,MS-Office 的 DOCX/XLSX 等即为 OfficeOpenXML 格式。

简介

MaltReport 实际上是一个通用的模板文档生成系统,其用途不仅用于生成报表,也可以用来生成合同、预算报告、标书等等任何需要格式与数据相结合的文档,其中的 XLS/ODS 模板尤其适合大量数据导出的场合。

简单来说,MaltReport 是通过直接在内存中解析操作 OpenDocument 和 OfficeOpenXML 文件来实现报表和单据的生成,整个理念非常接近于 ASP.NET MVC 的 Razor 模板,只不过 Razor 生成 HTML 而 MaltReport 生成 ODT/ODS/DOC/XLS 文件。

MaltReport 的优点:

所见即所得

  1. 通过在 OpenDocument 或 OpenOfficeXML 文件里嵌入简单易学的 Velocity 模板语言来开发模板,实际上我们将 MS-Office 和 LibreOffice 作为我们的所见即所得的报表模板编辑器。
  2. 生成后的报表是通用的 XLS/DOC/ODT/ODS 文件,打印、格式转换等均不是问题。
  3. 简单易用的 API,三行代码实现报表生成。

性能与可靠性

直接在内存中操作 odt/ods/xls/doc 文件,采用 NVelocity 模板引擎进行内容的替换,生成报表不依赖 Libreoffice/MS-Office 等软件,适合服务器端运行。因为 Word/Excel 这些桌面软件不是为服务器长期运行设计的,之前有些 Word 文档生成工具之类需要通过 Word 的 COM 接口操作 docx 文件,数量一大很有可能耗尽服务器的内存。

MaltReport 报表引擎本身不负责报表的排版和显示,因此没有其他采用像素定位设计的报表工具所存在的中文换行、对齐等等布局问题,极大提高了报表生成的性能。经实际使用的经验显示,生成报表的速度仅受限于磁盘 IO 速度.

特性完整

  1. 可以利用 LibreOffice Calc 或 MS-Excel 电子表格的强大功能,进行二次汇总分析或绘制图表。
  2. 支持图像数据,可以在文档中嵌入用户提供的图像数据。

还有最后不能不提及的,免费开源,MIT 协议授权,可在商业产品中自由使用。

使用说明

下面以 Word 报表为例介绍 MaltReport 的使用。

第一步,在 nuget 中加入项目引用:

MaltReport 已发布到 nuget.org 中,可通过 nuget 引入您的项目,参考:

https://www.nuget.org/packages/MaltReport2

第二步,创建报表模板

新建一个 Word 文档,并另存为【Word 2003 XML】格式,然后把文件扩展名从 xml 改回 doc,然后使用 Word 重新打开。

在 Word 中创建模板,报表引擎通过特殊的超链接及 Velocity 模板标记来识别,一点简单的小介绍:

  1. $xxx 是模板的占位符,通过 RenderContext 提供的数据进行替换,也支持 $xxx.yyy.zzz 或 ${xxx.yyy.zzz}这样的格式。
  2. 若表达式太长可使用超链接,超链接使用 rtl://$xxx.yyy.zzz/ 或rtl://${xxx.yyy.zzz} 的格式。
  3. 支持 foreach 循环和 if-then-else 条件等,尤其是表格可以按行或按列循环。

实际例子可参考 Velocity 的 VTL 语言文档及本项目的演示。

 当模板创建完成以后保存并关闭 Word。

Excel 的模板也是类似的操作:

注意,显示为 #VALUE! 的单元格是因为我们把此单元格设为数字格式,但是模板占位符不是数字所以 Excel 报错,但并不影响报表生成。

第三步,在 C# 代码里加载、渲染并生成报表

 1 var dt = new DataTable("Employees"); 2  3             //Fill the DataTable 4             var connectionString = @"Version=3,uri=file://./Database/northwind.db"; 5             using (var connection = new SqliteConnection(connectionString)) 6             { 7                 var sql = "SELECT FirstName, LastName, HireDate, BirthDate, Address FROM Employees"; 8                 var adapter = new SqliteDataAdapter(); 9                 adapter.SelectCommand = new SqliteCommand(sql, connection);10                 adapter.FillSchema(dt, SchemaType.Source);11                 adapter.Fill(dt);12             }13 14             var renderContext = new Dictionary<string, object>()15             {16                 //Plain old types17                 {"title", "EMPLOYEES"},18                 {"property1", "Property 1"},19                 {"property2", "Property 2"},20 21                 //Strong types22                 {"orm_employees",23                     new List<Employee>()24                     {25                         new Employee("Micheal Scott", "Address 1", 22),26                         new Employee("Andy Bernard", "Address 3", 33),27                         new Employee("Dwight Shurte", "Address 1", 22),28                         new Employee("Jim Halpert", "Address 2", 27),29                         new Employee("Pam Beesly", "Address 4", 19),30                     }31                 },32 33                 {"employees", dt}, //DataTable is ok34 35                 {"now", DateTime.Now}, //DateTime is ok too36             };

上面的代码演示了 RenderContext 的概念用法,RenderContext 为模板中所包含的数据的容器,本身是一个 IDictionary<string, object> 类型,key 为变量名,value 为变量值,变量值支持原始类型、强类型类、结构、DataTable 等。

有了模板和要填充到模板中的数据我们只需加载模板、编译模板然后渲染模板即可,非常简单直观的 API:

 1 var template = new WordMLTemplate(); 2  3 template.Load("template1.doc"); //第一步加载模板文件 4  5 template.Compile(); //第二步编译模板 6  7 //第三部渲染模板 8 var resultDoc = template.Render(ctx);  9 10 //第四步,保存生成的报表文件,也可保存到 MemoryStream11 using (var resultFile3 = File.Open("result.doc", FileMode.Create, FileAccess.ReadWrite))12 {13     resultDoc.Save(resultFile3);14 }

生成了名为“result.doc”的报表文件,试着用 Word 打开:

Voila! 全部搞定!

在项目的源代码里包含 Sandwych.Reporting.Demo 演示程序,里面包含生成 DOC/XLS/ODT/ODS 的全部样例。

下一步的开发计划

  1. 支持最新版 MS-Office 的 DOCX/XLSX 文档格式,因为我比较喜欢用 LibreOffice 做报表及打印工具,所以 MS-Office 的格式支持度没有 ODS/ODT 高;
  2. 支持二维码一维码图片生成及文档嵌入;
  3. 移植到 .Net Core,不过应该是个长期的过程,最少得等 .Net Core 2.0 出来以后。

常见问题解答

Q: 这到底是特么的什么东西?

A: 一句话来说 MaltReport 是 DOC/XLS/ODT/ODS 文档生成器。

 

Q: 这跟 NPOI 有什么区别?

A: MaltReport 只能生成不能读取 MS-Office 文件,但是单论生成的话 MaltReport 的性能远远超过 NPOI,而且不止一个数量级。MaltReport 跟 NPOI 的理念不同,不需要你用代码去设置 XLS/DOC 文件的样式、表格高度之类的格式工作,你直接在 Excel/Word 里设置好让 MaltReport 照着模板生成就可以了,程序需要提供的只是填充模板的数据。

 

Q: ODT/ODS 是什么文件,我怎么没见过?

A: ODT/ODS 是 LibreOffice/OpenOffice 使用的文档格式,ODT 等同于 DOCX、ODS 等同于 XLSX。LibreOffice 类似于免费开源版的 MS-Office。我们主力支持 ODS/ODT 文件是因为我们推荐使用 LibreOffice 作为报表设计、查看、打印及格式转换工具。举个例子来说,你可以把 LibreOffice 的“绿色版”打包到你的程序里,直接用作报表工具,这样难道不是很科学。还有更秒的是 LibreOffice 支持无界面后台网络服务的“无头”模式,你可以通过 RPC 直接访问 LibreOffice 的文件转换、打印各种功能。

关于调用 LibreOffice 实现文件格式转换请参考代码里的 Sandwych.Reporting.JODConverterDemo 项目。

项目地址及其他

联系我: oldrev AT gmail.com 也可加我 QQ: 55-43-1671

项目 github: https://github.com/oldrev/maltreport

项目 nuget:https://www.nuget.org/packages/MaltReport2

 

如果觉得本项目对您有用,您可以在 github 上给我点星星/fork,或者点击本文下方的“好文要顶”,您的赞赏是我不断完善本项目的动力。

0 0
原创粉丝点击