分享 Coding4Fun 專案裡的新嘗試 - 在 Linux 跑 ASP.NET Core 動態產生 Word 檔! 聽起來很酷吧?

OpenXML SDK 從 2.7.0 (2017/1) 起支援 .NET Standard 1.3 (延伸閱讀:.NET Standard 2.0 是什麼?可以吃嗎?), 換言之,OpenXML SDK 已支援 .NET Core,可跨平台在 Linux 執行沒問題。

過去我有一些用 OpenXML SDK 處理 Word 的經驗:

但建立表格是第一次,放在 Linux 跑更是破天荒。

構想是這樣的。我想依據傳入的英文單字陣列產生一張測驗卷,題目以表格排列,每個單字有英文題目與中文填空兩欄,每列放兩個單字共四欄。 我先做了個範本 Word,隨意放上頁首圖示、標題與頁碼,搞定邊距、字型大小等排版設定,這部分程式也能處理,但 GUI 人工處理直覺省事一些:

要依據範本產生新文件,無腦做法是將範本複製成新檔進行編輯,但在伺服器產生暫存檔需打通存取權限並有事後刪除問題,全程在記憶體裡做完才是王道, 而 OpenXML SDK 支援使用 MemoryStream 的不落地式解法。微軟的官方文件https://docs.microsoft.com愈來愈完整好讀, 靠著兩篇範例就寫出我要的功能:

完整程式碼如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.AspNetCore.Hosting;

namespace EngVoc7000.Model
{
    public class WordMaker
    {
        public static byte[] GenVocQuizPaper(string tmplPath, string[] vocList)
        {
            var tmplContent = File.ReadAllBytes(tmplPath);
            using (var ms = new MemoryStream())
            {
                ms.Write(tmplContent, 0, (int)tmplContent.Length);
                using (var doc = WordprocessingDocument.Open(ms, true))
                {
                    
                    var tbl = new Table();
                    //設定框線
                    var tp = new TableProperties(
                        //指定田字形六條線的樣式及線寬
                        new TableBorders(
                            //Size 單位為 1/8 點 [註]
                            new TopBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 8 },
                            new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 8 },
                            new LeftBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 8 },
                            new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 8 },
                            new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 8 },
                            new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 8 }
                       )
                    );
                    tbl.AppendChild<TableProperties>(tp);
                    var que = new Queue<string>(vocList);
                    //A4 直式,兩欄
                    while (que.Any())
                    {
                        var tr = new TableRow();
                        //每一列放四欄
                        for (var i = 0; i < 2; i++)
                        {
                            var tc = new TableCell();
                            //第一欄為單字
                            tc.Append(new TableCellProperties(new TableCellWidth()
                            {
                                //寬度取15%
                                Type = TableWidthUnitValues.Pct,
                                Width = "15"
                            }));
                            var text = que.Any() ? que.Dequeue() : string.Empty;
                            tc.Append(new Paragraph(new Run(new Text(text))));
                            tr.Append(tc);
                            //第二欄為填空
                            tc = new TableCell();
                            tc.Append(new TableCellProperties(new TableCellWidth()
                            {
                                Type = TableWidthUnitValues.Pct,
                                Width = "35"
                            }));
                            tc.Append(new Paragraph(new Run(new Text(string.Empty))));
                            tr.Append(tc);
                        }
                        tbl.Append(tr);
                    }
                    doc.MainDocumentPart.Document.Body.Append(tbl);
                }
                return ms.ToArray();
            }            
        }
    }
}

【註】OpenXML 使用的尺寸單位比較特別,包含:(參考:Points, inches and Emus: Measuring units in Office Open XML)

  • dxa (Twentieths of a point),代表一個點( Point )的二十分之一,每一英吋有 72 個點。
  • Half-Points,用於字型,12pt 等於 24 half-points
  • Pct,百分比,用於表格寬度、欄位寬度及邊距(Margin)
  • EMU,English Metric Unit,用於向量繪圖及內嵌圖,1 吋 = 914400 EMUs

但線寬單位不在其中,在 MSDN 論壇有人提到線寬以 1/8 點( 1/8 Points Unit)為單位(24=3 Points),但我沒找到精確術語或定義,若有人知道請留言指點。

輸出成品如下:

OpenXML SDK 對我不是什麼新鮮事兒,但用 C# 在 Linux 主機生出 Word 文件感覺就是爽,哈!

Sample code of generating Word table with .NET Core.


Comments

Be the first to post a comment

Post a comment


90 - 25 =