2011年9月23日 星期五

asp.net_利用open xml於word套版列印

在每一個單位,每一個處室,不管是公家還是私人,每一個有人在的地方,通常都會有一個需求:我要列印資料。

這時候我們應該可能也許,就會把資料匯成xls、doc、txt、csv,並且跟他說:印吧!

接著,他會說:我要按照我的格式(中式表格:A儲存格跟B左右合併、C跟D上下合併、標題字大之類的),那麼我們就會依照這個格式做一個相同的html檔案,把從資料庫撈出來的資料放到該放的位置,接著說:棒吧!按照你格式的表格。

接著,某些"精實的"外星人就會說:你這....感覺不是word,就是跟我原本的表格長得不太一樣,不能做一樣嗎?這樣我很困擾耶。

好!一般如我的工程師這時候就會放空,然後說服他:你看word跟我的html用word開根本就一模一樣、一模一樣、一模一樣(晃晃晃)

總之,以往在處理類似這樣的功能,都需要花費很大的力氣才能完成一張,有時候表格很複雜的時候更是讓人想要見見原本設計表格的人(?),最近同事又遇到類似的狀況,需求的單位"一定要"作出"一模一樣"的表格列印功能。

最後同事給我三個關鍵字:有空嗎、黑暗執行緒、套版列印跟一個網址
----------------------------------------------------------------

依照黑大的相關文章,也試做了一下整個流程,我個人是覺得效果非常的好,好到我覺得我以前是呆子。

觀念:office2007以後使用標準的openxml作為檔案的定義方式,所以我們可以藉由修改xml的方式來置換已經於word裡面的文字。所以我們可以做好樣板→置換文字→下載檔案的方式來完成套版列印的功能。

流程:
1. 下載需要的sdk(Open XML SDK 2.0 for Microsoft Office)
進到下載頁面以後,會看到兩個可以下載的項目(OpenXMLSDKTool.msi與OpenXMLSDKv2.msi),OpenXMLSDKv2是程式開發所需要使用的SDK,OpenXMLSDKTool則是觀看openxml的工具。


2. 安裝剛剛所下載的兩個msi檔案。

3. 開啟一個專案檔(asp.net),並將需要的dll複製到bin資料夾。
A. DocumentFormat.OpenXml.dll:這個檔案為OpenXMLSDKv2所附的,位置在C:\Program Files (x86)\Open XML SDK\V2.0\lib。
B. WindowsBase.dll:這個為framework原本就有的檔案,位置在C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0。

4. 準備一個docx的樣版(上面有提到office2007才更改為openxml的方式,所以該方法僅適用於docx檔案)。
這個樣板的範例是模仿黑大的方式,需要置換的內容利用"[$$]"包起來,但實際上這是一個提供程式辨別的代號,如果想要使用別種符號定義也可以。

5. 撰寫程式碼
A. 將要放入樣板的資料以Dictionary包裝,比如說我要放入四個資訊:

Dictionary<string, string> dataObject = new Dictionary<string, string>();
dataObject.Add("Name","Ola");
dataObject.Add("Tel", "123");
dataObject.Add("Address", "台北市");
dataObject.Add("Mail", "wangshifu1220@gmail.com");


B. 準備兩個路徑(一個為樣板的原始路徑、另一個為填寫內容後檔案的路徑)

C.置換openxml的程式碼(參考黑大文章)

public static byte[] MakeDocx(string tempFile, string templateFile, Dictionary dct)
{
File.Copy(templateFile, tempFile);
using (WordprocessingDocument wd = WordprocessingDocument.Open(tempFile, true))
{ parse(wd.MainDocumentPart, dct);}
}

private static void parse(OpenXmlPart oxp, Dictionary<string, string> dct)
{
string xmlString = null;
using (StreamReader sr = new StreamReader(oxp.GetStream()))
{ xmlString = sr.ReadToEnd(); }
foreach (string key in dct.Keys)
{ xmlString = xmlString.Replace("[$" + key + "$]", dct[key]);}
using (StreamWriter sw = new StreamWriter(oxp.GetStream(FileMode.Create)))
{ sw.Write(xmlString); }
}

整個道理就是程式在MakeDocx先複製一份樣板檔案,然後讀取WordprocessingDocument的內容,並且交給parse的函式;而在parse函式內將該內容以StreamReader.ReadToEnd()的方式讀取出來,並且去尋找出文件內有[$$]的地方,置換成我們預先儲存在Dictionary的內容。

所以上面[$Name$]的部分就會被置換成ola。

-----------------------------------------------------
依照上述的步驟我們就可以很方便的先處理樣板的docx,並且用置換字串的方式動態改變內容,再將完成的檔案讓使用者下載,來完成一個"完全一模一樣格式"的匯出或列印功能。

注意:在實作過程中,有可能會發生文字無法置換的情況,原因是在進行樣板docx設計時,有可能因為我們的操作,而讓辨識的內容(指文中的[$$])間存在了很多不應該出現標籤,而導致程式無法辨識,若要確認是否因為該原因可以利用Open XML SDK 2.0 Productivity Tool(OpenXMLSDKTool.msi安裝後)來開啟docx檔,即可觀看openxml的內容,用以確認。

6 則留言:

kolen 提到...

強者ola哥,有空嗎(關鍵字)??

ola的家 提到...

有空有空,你要參加富邦半馬嗎?

劉邦威 提到...

您好 請教一下 "文字無法置換的情況" 這情況該如何解決?
用openxml SDK tool去修改嗎? 還是?
明明輸入的就是[$test$] 但是用tool看中間會多很多符號
感謝您的解答

ola的家 提到...

[$test$]中間多很多符號,代表你在輸入的時候有用到其他功能,導致Word自己塞進他需要的tag。

所以你可以嘗試[→$→t→e→s→t→$→]順序輸入,應該就可以正常。

劉邦威 提到...

前輩您好
有照您的方法做 , 但是有些[$$]中間還是會有多符號
最後解決方法如下
1.整張word都先打入要替換的文字
2.修改副檔名為zip
3.解壓縮 找出document.xml
4.再用XML編輯器(firstobject)把缺少的符號寫進去多餘的符號刪除
5.壓縮回zip , 修改副檔名回docx
6.再開啟程式測試 替換文字便OK
謝謝您的解答 , 也給有相同問題的人一個解決方法

陳慶文 提到...

大大可以給範例嗎? 真的一直試不出來啊
@@ 感激萬分!~

張貼留言