使用Asponse.Words處理Word模板
一.客戶需求
近期接到一個專案,在與客戶初步溝通後,客戶描述的需求聽起來也非常簡單,就是目前客戶需要在Excel錄入資料,然後把這些資料分別複製到多個Word的多個地方,除了單個值之外,還需要複製表格資料以及圖片資料,客戶覺得這麼操作一是容易出錯,二是重複操作的工作量太大。在初步瞭解使用者的需求之後,得知客戶需求的核心功能就是在Word中填充資料來源,需要填充資料的資料來源包括文字,表格以及圖片等,本文以此為出發點,重點介紹如何在Word中使用“域”來填充外部資料。
二.外掛選型
目前處理Word等Office文件型別的控制元件,微軟自帶的Com元件問題實在太多,一個比較麻煩的問題就是部分Com元件需要註冊,並且如果客戶端與開發電腦使用的Com元件版本不一致,還會出現各種問題,因此選擇了Asponse.words外掛,該軟體為收費外掛,具體的收費標準可以在官網進行檢視。
三.模板製作
利用Asponse進行資料填充,其實程式碼不難,核心的工作就是需要在Word模板中設定標記,也就是需要讓程式知道在什麼地方填充資料,目前做標記的方式有兩種,一種是使用書籤,一種是使用域。目前網上大多的案例都是使用書籤,但是在我實際開發的過程中,建議大家使用“域”,而不是使用書籤,原因有以下幾點:
1.書籤不能重複新增,比如我在第一個空白出需要插入資料來源“姓名”,在最後簽名處還要插入“姓名”,這個時候使用“域”的話可以在兩處都插入“姓名”域,但是如果使用書籤,需要設定不同的書籤名稱,生成資料來源的時候會增加工作量
2.書籤不能在文件中直觀的展示出來,如果插入書籤比較多,很容易造成混亂
此外,需要特別說明的是,製作書籤或者“域"的時候務必務必使用Word而不是WPS製作,因為目前發現的一個問題就是,使用WPS製作的書籤或者是”域“,在填充資料之後會自動增加一行空行,這個可能是WPS與Word的內部機制不同;還有一個技巧,在文件中使用Alt+F9,可以檢視到模板的各種域程式碼,如下圖所示:
四.插入書籤/域
1.插入書籤
2.插入域(插入->文件部件->域,選擇"MergeField")
五.實現程式碼
1.獲取文件
Aspose.Words.Document doc = new Aspose.Words.Document(filePath); Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(doc);
2.利用word模板填充資料
List<string> filedsValueList = new List<string>(); string[] filedsName =doc.MailMerge.GetFieldNames();//獲取文件中所有的域 for (int i = 0; i < filedsName.Length; i++) { if (dataTable.Columns.Contains(filedsName[i])) { filedsValueList.Add(dataTable.Rows[0][filedsName[i]].ToString()); } else { filedsValueList.Add(""); } }
//核心程式碼其實就是這一句,上面的都是組織資料來源
//引數是兩個陣列,第一個陣列是文件中所有”域“的名稱,第二個是所對應域的值 doc.MailMerge.Execute(filedsName, filedsValueList.ToArray());
3.插入圖片
插入圖片並不需要特殊的程式碼,而是需要對Word模板中的域做特殊設定,設定的方式為:
在彈出來的對話方塊中,把”域“名稱的前面加上"Image:",如下圖所示:
設定好之後,只需要將該域的值設定為圖片的路徑,即可在文件中展示圖片,如果需要在程式碼中控制圖片的大小,需要給文件繫結圖片處理的回撥事件,程式碼如下:
doc.MailMerge.FieldMergingCallback = new HandleMerFieldInsert();
4.設定圖片尺寸
在Asponse直接提供的方法中,沒有修改圖片尺寸的方法,但是可以重寫Asponse的IFieldMergingCallback類,用於設定圖片大小
class HandleMerFieldInsert : IFieldMergingCallback { //文字處理 void IFieldMergingCallback.FieldMerging(FieldMergingArgs e) { } //圖片處理 void IFieldMergingCallback.ImageFieldMerging(ImageFieldMergingArgs args) { Document doc = args.Document; DocumentBuilder builder = new DocumentBuilder(doc); builder.MoveToMergeField(args.FieldName); Shape shapeImage = builder.InsertImage(args.FieldValue.ToString()); //設定x,y座標和高寬. shapeImage .Left = 0; shapeImage .Top = 0; shapeImage .Width = 50; shapeImage .Height = 25; } }
5.填充表格
填充表格資料,需要在模板中先設定表格繫結資料的起始位置,然後在每一列中設定資料來源中的列名稱,具體步驟如下圖:
表格資料來源的起始標記為”TableStart“,結束標記為"TableEnd",設定好表格資料來源的起始與結束標記之後,再在每一列中單獨設定每一列需要繫結的欄位名稱即可,設定好的資料來源如下圖所示:
通過Alt+F9可以看到設定好的各種域的程式碼,如下圖所示:
設定好表格的各個域之後,通過如下程式碼完成對資料來源的填充:
dt.TableName = "UserInfo";//這裡的表格名稱必須和模板中表格的起始與結束源名稱相同
doc.MailMerge.ExecuteWithRegions(dt);
6.刪除表格及對應的佔位符
使用Asponse進行刪除的操作相對比較複雜,現有的業務是需要刪除模板中的某一個表格,但有個問題就是,在刪除了該表格之後,該表格所在頁面的佔位符還在,會導致生成的文件有一個空白頁,因此在刪除類似表格,圖片這種元素時,還需要刪除對應的段落佔位符
NodeCollection nodeCollection = doc.GetChildNodes(NodeType.Table, true);//獲取所有表格 foreach (Table table in nodeCollection) { if (table.GetText().Contains("AAAAAA") && table.GetText().Contains("BBBBBB"))//To Do:這裡通過獲取表格中的內容來判定是否為刪除的表格,應該還有更好的辦法 { Paragraph paragraph = (Paragraph)table.PreviousSibling; paragraph.Remove();//刪除段落 table.Remove();//刪除表格 } }
7.儲存帶密碼的PDF
Aspose.Words.Saving.PdfSaveOptions saveOption = new Aspose.Words.Saving.PdfSaveOptions(); saveOption.SaveFormat = Aspose.Words.SaveFormat.Pdf; PdfEncryptionDetails encryptionDetails = new PdfEncryptionDetails(pdfPwd, string.Empty, PdfEncryptionAlgorithm.RC4_128); encryptionDetails.Permissions = PdfPermissions.AllowAll; saveOption.EncryptionDetails = encryptionDetails; doc.Save(fullfilepath + ".pdf", saveOption);
8.刪除未被賦值的“域”
doc.MailMerge.DeleteFields();
寫在最後
至此,Asponse利用模板處理資料的常規方法總結完畢,對於直接使用Asponse的方法,在Word中通過硬編碼的方式增加表格建議不到萬不得已不要使用,因為增加表格需要控制表格本身的樣式,還需要控制單元格的樣式,並且對於複雜的文件,定位表格也會增加難度。