網友ping留言問了JS DOCX套版元件問題,由其所提供下載位置(https://github.com/djpate/docxgen)的Readme文件,判斷是PHP所開發,直覺地認為所謂JS套版是JavaScript呼叫PHP完成。但ping後續補充: 真的是純JavaScript,並提供可執行的程式包,我這才驚覺:

啥咪!! 真有神人用純JavaScript寫出DOCX套版元件?

DOCX的本質是ZIP壓縮打包的一堆XML檔案,理論上只要能解壓ZIP、解析及操作XML,就能完成文件修改。但從沒想過這一切可以全用JavaScript解決? node.js揮軍Server端,Espruino殺進嵌入系統,今天的JavaScript,沒有極限!

做了簡單解析,發現它依賴base64.js(Base64編碼)、jszip.js(ZIP壓縮解壓),其餘只靠一個docxgen.js搞定全部工作。要執行套版時,只要先準備一個Word文件,在其中穿插{ tag1}、{tag2}註明要置換成其他文字的位置,執行如下JavaScript,就可得到套版後的Word檔。

排版顯示純文字
new DocxGen().loadFromFile("tagExample.docx", { async: true })
.success(function(doc){
    doc.setTags({ tag1:"tag1Value", tag2:"tag2Value" });
    doc.applyTags() //apply them replace all occurences of {tag*}
    doc.output() //Output the document using Data-URI
});

原程式的tagExample.docx需透過XHR存取,Chrome預設開啟本機HTML執行時不允許XHR存取本地磁碟機檔案,嫌外加Chrome啟動參數麻煩,又不想為此丟到IIS測試,於是用了Object URL技巧,改選取本機檔案作為XHR下載對象。如此,就能直接在本機用Chrome測試。操作示範如下:

tagExample.docx內含{last_name} {first_name}等標籤,在<textarea>編輯JSON字串定義好first_name, last_name等要置換的文字,選取檔案後按下【套版】,馬上能下載套版好的Word檔,其中{last_name}等標籤都已被換成指定的文字。但示範也突顯ping所說的中文變亂碼問題。例如: "黑暗執行緒"變成"黑暗執行緒"。

既是純JavaScript,就一定能Trace Code、找出問題並修正。想到這裡,手就癢了,馬上開啟Chrome偵錯工具,找到docxgen.js。但發現它被Minify壓縮:

不怕,點一下左下的Pretty print鈕,Chrome立刻將JavaScript程式碼縮排整理妥當,恭請長官審閱:

設下中斷點一路追蹤,查出一處可疑:

DocUtils.encode_utf8 = function (e) {  return unescape(encodeURIComponent(e));  }

函式目的應是將文字轉為utf8編碼,但感覺套在中文會出包。以console測試unescape(encodeURIComponent("黑暗執行緒")),果然傳回"黑暗執行緒",跟Word成品中的亂碼一致,驗證是encode_utf8把中文轉壞了!

如果這樣不行,該怎麼克服? 想起"&#unicode;"的Unicode字元表示法,將encode_utf8改成:

DocUtils.encode_utf8 = function (e) {
        var r = [];
        for (var i = 0; i < e.length; i++) {
            var asc = e.charCodeAt(i);
            r.push("&#" + asc + ";");
        }
        return r.join("");
    }

雖然轉為"&#nnnn;"後長度會增加,至少確保編碼正確無誤。薑!薑!薑!薑~ Bug被修掉囉!

最後,花一點時間聊聊這個JavaScript版套版元件—docxgen.js。

網路上關於它的討論很少,較完整的說明只有法國javascript-ninja網站的Demo網頁,由網站直接瀏覽目錄找到Readme.md(文件寫入時間是2014-2-18),說明裡提到它支援Chrome 26+、Firefox 3+,Safari沒測過,IE不行(連IE10都不行,理由是XHR無法處理純Binary檔案)。由於檔案日期很新,或許是個尚未公開的Open Source Project吧! 我個人認為,直接置換XML {tag}的做法在遇到Word儲存的複雜樣式時,可能還有些地雷要掃。若限定必須在非Windows主機直接進行DOCX套表,這絕對是很出色的解決方案。


Comments

# by sean

黑大,有文句不順~ "我但沒過"這一切可以全用JavaScript解決

# by Jeffrey

to sean, 恭喜發現防盜文浮水印(大誤 orz) 謝謝指正

# by ping

黑大果然真神人也... 不過另一神人也幫助我解決這個問題了 一時高興就給他忘記來回覆一下了 請參閱 http://ithelp.ithome.com.tw/question/10147038 只要刪除掉一小段即可... 你們都太強了...我去玩沙先...謝

# by 亨利

請問黑大 這套件是否可以用在傳統的asp上使用,還是黑大有更好的建議。 謝謝

# by Jeffrey

to 亨利,docxgen是純JavaScript元件,只要能顯示HTML的平台就能應用,與後端無關。故在ASP中使用docxgen是可行的,但它對瀏覽器有較高的要求,據我所知,很多ASP限定只能在舊IE上執行,反而是較大的問題(如果你們的ASP可以在Chrome上執行,就不用煩惱了)。如果不用docxgen,.NET有NPOI、OpenXML SDK及Office Automation等選擇,如果要由ASP呼叫,可考慮用.NET寫成元件(要用CCW轉成ActiveX元件)或服務,但有一定的複雜度。另一種管道是購買AcitveX元件,要花錢但省事很多。

# by 亨利

謝謝黑大的回覆,我公司的使用的是傳統的asp ,改版後目前是可以在ie11 跟 chrome 上執行,伺服器也可以上到windows 2012 server , 資料庫也可以升級到SQL 2012 。我目前的問題是要把資料庫裡的資料,套印出來,原本想用 CrystalReport 但是對傳統asp 資源很少,以前都是用網頁直接做出來,但是很累,不用的瀏覽器印出來的會有差異,所以就想用docxgen來套印,後來又看到104人力銀行的列印履歷表是下載xml檔,可以直接用WORD開啟,不知docxgen 可以直接用在xml檔嗎?

# by 亨利

黑大,您好 之前說的xml我做出來了,就是把它當成是txt檔,用asp讀出來,然後用replace 把預先設定的TAG置換,然後再另存檔案就行了。

# by Jeffrey

to 亨利,如果套表格式固定不常變動,這不失為一個好方法,謝謝分享。

# by ken

黑大, 你好, 我想試這個 JavaScript版的 DOCX套版元件 但一執行流覽器就有錯誤 ( IE跟chrome都一樣 ). 錯誤訊息是 : Uncaught ReferenceError: exports is not defined(anonymous function) @ base64.js:7 Uncaught TypeError: l.XmlUtil is not a function(anonymous function) @ docxgen.js:1 Uncaught ReferenceError: DocUtils is not defined(anonymous function) @ main.js:1 看起來好像, 每個載入的 js檔都有問題. 請問是我什麼地方搞錯了嗎 ?

# by ken

to 黑大: DEMO不會耶..可以順利下載置換好的 DOCX 檔

# by Jeffrey

to ken, 有成功的樣本可供參照就好辦多了,下一步設法找出你的實驗環境與Demo網站存在的差異,如果查不出來,看能否放到Internet上由大家幫忙看看。

# by ken

好像也沒什麼CODE可以請大家看. 其實我只是下載 ping 大當時提供的鏈結 http://www.net-tw.net/test/docx.zip 1.解壓後, 整個目錄放到 IIS去. 2. 再把Contract.asp 的第一行刪掉 , 把檔名改成Contract.html <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%> 3. 再把Contract.html 裏的 template 路徑改成我IIS 的URL http://www.net-tw.net/test/tagExample.docx 然後在流覽器一測就出錯了. ><"

# by hch

to 黑大: 請問最後套版後 1:如果是要直接開啟,不是要下載存檔。要怎麼改? 2:如果是要直接列印。要怎麼改? 謝謝!

# by Jeffrey

to hch, 直接開啟及列印Word文件需要靠第三方元件或套件支援,各瀏覽器不同,實做細節得配合套件要求。例如: Chrome:https://goo.gl/FECph2

# by Cliffkai

黑大你好 在套版的過程中 遇到word中 如果有事先預設的中文 則會出現caught error的錯誤

# by Jeffrey

to Cliffkai, 看不懂「Word中有事先預設的中文」

Post a comment