[ASP .NET]用TemplateEngine.Docx套版產出Word檔

[ASP .NET]用TemplateEngine.Docx套版產出Word檔

工作上常需要處理Excel或Word檔,以往都用Microsoft.Office.Interop來處理,但這有幾個問題:

  1. 主機需安裝 Microsoft Office Excel/Word 2007 或更新版本。
  2. 處理時容易產生很多未關閉的檔案,用掉大量的記憶體,造成主機效能變差(參考KB255757)。

Excel可參考此篇用NPOI處理,Word可用TemplateEngine.Docx處理簡單的套版產出。

首先建立樣板檔:

建立新的Word檔,先將【開發人員】功能開啟:依序選擇檔案→選項→自訂功能區→將開發人員功能開啟:

再來開始設定樣版內容:

代換一般內容:選取要代換的內容[1]後,選擇開發人員[2]→開啟設計模式[3]→插入RTF內容控制項[4]→按下屬性5]→設定標籤名稱[6]後按確定

選取的內容會變成用標籤包起來的樣式即表示設定完成,可自行變更標籤內文字做為要帶入的內容說明。

代換表格:先建立好表格表頭及一列內容,依照代換一般內容作法,先將每個欄位的資料標籤建好,再選取整列[1]→插入重複區段內容控制項[2]→按下屬性5]→設定標籤名稱[6]後按確定

設定成功後,該列會再被雙層的標籤包起。

如要在每個頁面顯示表頭,可選取表頭(可選擇多列)後按右鍵→表格內容→列→勾起[標題列在每頁頂端時重複]

代換重複區塊:實務上常常要產出個人報表之類的文件,此時可以先插入一個分頁符號後,將要重複的部分全選取起來,設定一個RTF內容控制項

PS.將分頁符號包起來雖然可以在每一次重複資料跳到新的一頁,但最後完成的檔案一定會多一個空白頁,需靠手動移除。

這樣基本樣板就完成了,再來處理程式部分,先由NuGet搜尋Doc即可安裝TemplateEngine.Docx

基本的程式如下,依照樣板內設定好的標籤,以FieldContent代換RTF,TableContent代換表格,如要重複某些內容,把Field及Table丟到RepeatContent中,統一丟到Content裡,

複製一份Template檔案,將Content丟到複製好的檔案做代換處理,儲存好變更後的檔案即可:

var fillContent = new Content();
List<IContentItem> fields = null;
TableContent tableContent = null;

//FieldContent → 代換一般內容(RTF)
fields = new List<IContentItem>();
fields.Add(new FieldContent("@title", $"title{i.ToString()}"));

//TableContent → 代換表格並依照資料數自動產生列
tableContent = new TableContent("@row");
for (int k = 0; k < 2; i++)
{
    //設定表格中要代換的RTF
    tableContent.AddRow(
        new FieldContent("@name", $"name{k.ToString()}"),
        new FieldContent("@address", $"address{k.ToString()}"),
        new FieldContent("@sex", k == 0 ? "男" : "女")
    );
}
//RepeatContent要重複的部分都丟到這裡面
var repeatContent = new RepeatContent("@patient");

for(int i = 0; i < 2; i++)
{
	fields = new List<IContentItem>();
	fields.Add(new FieldContent("@title", $"title{i.ToString()}"));
	
	tableContent = new TableContent("@row");
	for (int k = 0; k < 2; i++)
	{
		//設定表格中要代換的RTF
		tableContent.AddRow(
			new FieldContent("@name", $"name{k.ToString()}"),
			new FieldContent("@address", $"address{k.ToString()}"),
			new FieldContent("@sex", k == 0 ? "男" : "女")
		);
	}
	
    fields.Add(tableContent);
    repeatContent.AddItem(fields.ToArray());
}

//最後把要代換的所有資料丟到Content內
fields.ForEach(f => fillContent.Fields.Add(f as FieldContent)); //一般內容丟Fields
fillContent.Tables.Add(tableContent); //表格丟Tables
fillContent.Repeats.Add(repeatContent); //重複的丟Repeats

//複製 Template 檔案
System.IO.File.Copy("Template.docx", "Copy.docx");

//將Content丟給TemplateProcessor處理,SetRemoveContentControls=true表示要清除標籤內文字,如不要清除則設為false
using (var outputDocument = new TemplateProcessor("Copy.docx").SetRemoveContentControls(true))
{
    outputDocument.FillContent(fillContent);
    outputDocument.SaveChanges(); //儲存變更檔案
}

return new FileStream("Copy.docx", FileMode.Open, FileAccess.Read);

該套件還可以處理List及Image的代換,最大的好處是他可以處理無限層的槽狀資料,可以在Table、List中塞入無限層的Table、List、Field,如下圖說明

參考資料

https://github.com/UNIT6-open/TemplateEngine.Docx - 有其他範例可以參考

https://weekly-geekly.github.io/articles/269307/index.html