UPDATED: 本文僅適用 MaltReport 2.x ,3.x 版本文檔還在撰寫當中,目前請參考項目中的 Samples。
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 的優點:
所見即所得
- 通過在 OpenDocument 或 OpenOfficeXML 文件里嵌入簡單易學的 Velocity 模板語言來開發模板,實際上我們將 MS-Office 和 LibreOffice 作為我們的所見即所得的報表模板編輯器。
- 生成后的報表是通用的 XLS/DOC/ODT/ODS 文件,打印、格式轉換等均不是問題。
- 簡單易用的 API,三行代碼實現報表生成。
性能與可靠性
直接在內存中操作 odt/ods/xls/doc 文件,采用 NVelocity 模板引擎進行內容的替換,生成報表不依賴 Libreoffice/MS-Office 等軟件,適合服務器端運行。因為 Word/Excel 這些桌面軟件不是為服務器長期運行設計的,之前有些 Word 文檔生成工具之類需要通過 Word 的 COM 接口操作 docx 文件,數量一大很有可能耗盡服務器的內存。
MaltReport 報表引擎本身不負責報表的排版和顯示,因此沒有其他采用像素定位設計的報表工具所存在的中文換行、對齊等等布局問題,極大提高了報表生成的性能。經實際使用的經驗顯示,生成報表的速度僅受限於磁盤 IO 速度.
特性完整
- 可以利用 LibreOffice Calc 或 MS-Excel 電子表格的強大功能,進行二次匯總分析或繪制圖表。
- 支持圖像數據,可以在文檔中嵌入用戶提供的圖像數據。
還有最后不能不提及的,免費開源,MIT 協議授權,可在商業產品中自由使用。
使用說明
下面以 Word 報表為例介紹 MaltReport 的使用。
第一步,在 nuget 中加入項目引用:
MaltReport 已發布到 nuget.org 中,可通過 nuget 引入您的項目,參考:
https://www.nuget.org/packages/MaltReport2
第二步,創建報表模板
新建一個 Word 文檔,並另存為【Word 2003 XML】格式,命名為“template1.xml”。注意這里 Word 會把文件的擴展名設為 XML。

在 Word 中創建模板,報表引擎通過特殊的超鏈接及 Velocity 模板標記來識別,一點簡單的小介紹:
- $xxx 是模板的占位符,通過 RenderContext 提供的數據進行替換,也支持 $xxx.yyy.zzz 或 ${xxx.yyy.zzz}這樣的格式。
- 若表達式太長可使用超鏈接,超鏈接使用 rtl://$xxx.yyy.zzz/ 或rtl://${xxx.yyy.zzz} 的格式。
- 支持 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 types 17 {"title", "EMPLOYEES"}, 18 {"property1", "Property 1"}, 19 {"property2", "Property 2"}, 20 21 //Strong types 22 {"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 ok 34 35 {"now", DateTime.Now}, //DateTime is ok too 36 };
上面的代碼演示了 RenderContext 的概念用法,RenderContext 為模板中所包含的數據的容器,本身是一個 IDictionary<string, object> 類型,key 為變量名,value 為變量值,變量值支持原始類型、強類型類、結構、DataTable 等。
有了模板和要填充到模板中的數據我們只需加載模板、編譯模板然后渲染模板即可,非常簡單直觀的 API:
1 var template = new WordMLTemplate(); 2 3 template.Load("template1.xml"); //第一步加載模板文件 4 5 template.Compile(); //第二步編譯模板 6 7 //第三部渲染模板 8 var resultDoc = template.Render(ctx); 9 10 //第四步,保存生成的報表文件,也可保存到 MemoryStream 11 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 的全部樣例。
下一步的開發計划
- 支持最新版 MS-Office 的 DOCX/XLSX 文檔格式,因為我比較喜歡用 LibreOffice 做報表及打印工具,所以 MS-Office 的格式支持度沒有 ODS/ODT 高;
- 支持二維碼一維碼圖片生成及文檔嵌入;
- 異步 IO 支持;
- 移植到 .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
附加福利:支持圖片、支持 .NET Standard 1.6 的開發版本在 vnext 分支里。
很慚愧,就做了一點微小的工作。如果覺得本項目對您有用,您可以在 github 上給我點星星/fork,或者點擊本文下方的“推薦”,您的贊賞是我不斷完善本項目的動力。
