[ASP .NET]用TemplateEngine.Docx套版產出Word檔
工作上常需要處理Excel或Word檔,以往都用Microsoft.Office.Interop來處理,但這有幾個問題:
- 主機需安裝 Microsoft Office Excel/Word 2007 或更新版本。
- 處理時容易產生很多未關閉的檔案,用掉大量的記憶體,造成主機效能變差(參考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 - 有其他範例可以參考