簡易由網頁自動輸出 Office 文件
由於企業內部或政府部門經常使用Office文件,使得透過網站功能自動輸出Office文件成為大量的需求,甚至部分網頁系統在政府採購標單內指定要求此功能;要輸出成為Office文件,大部分採用Automation (DCOM)方式,以物件操控方式建立,在這類前提下,只能選擇ASP/ASP.NET作為建立的網頁平台。
而即使使用物件操控建立,網頁使用者權限不足,開發者接著就是面對一連串的權限調整,甚至到最後還是無法正確完成權限設定,在ASP.NET可以以不同使用者權限執行,在此方面有較佳的彈性,但是提高網頁應用程式的權限時,可能Server遇到被攻擊的風險也跟著升高,而二進位的Office也可能因Server的Office遭受巨集病毒感染,而大量散佈到Client端。
此外,以物件方式建立尚需面臨由Server轉送至Client端前需要產生暫存文件,以ASP開發更需複雜的暫存文件管理機制,以避免同時存取發生鎖死及磁碟空間管理,若發生程式碼錯誤或使用者中斷,可能導致Office軟體無法正確從記憶體中釋放、或是轉送之暫存檔無法刪除等問題而拖垮系統資源,亦有Server端執行物件帳號來自動產生之Office暫存檔管理困擾;也因Office文件建立時,需耗費大量記憶體,且執行較為緩慢,多人同時瀏覽相同網頁會拖累系統效能或導致鎖死。以資策會目前正在執行部分政府委辦計畫為例,資策會選用IStart元件產生Excel報表及PowerPoint簡報,係屬在Client端以DCOM方式存取,執行速度緩慢,一份5 ~ 8頁制式格式簡報檔可能需時3 ~ 5分鐘才能自動完成,若中間發生網路連線問題或使用者中斷,都容易產生DCOM的資源無法正確被釋放。
在Office XP/2003以後直接支援HTML檔案,只要妥善運用就可輕易的匯出成為Office文件,下面先介紹一個簡單同時支援Word、Excel及PowerPoint的範例:
<%@ Page Language="vb" AutoEventWireup="false" CodePage=”950" %>
<script language="vb" runat="server" id="modOffice">
Public Function SetResponseHeader(Byval sContentType As String, Byval sFileName As String, _
Byval bSaveFile As Boolean)
Dim sContentDisposition As String
With Response
If bSaveFile Then
sContentDisposition = "attachment; " ' 強制存檔,未設定則依瀏覽器預設開啟或存檔
End If
If Len(sFileName) > 0 Then
sContentDisposition = sContentDisposition & "filename=" & sFileName ' 檔名
End If
If Len(sContentDisposition) > 0 Then
.AddHeader("Content-disposition", sContentDisposition)
End If
.ContentType = sContentType
End With
End Function
</script>
<%If Len(Request.QueryString("ext")) > 0 Then
SetResponseHeader(Request.QueryString("ContentType"), "Office." & Request.QueryString("ext"), False)
End If%>
<HTML>
<HEAD>
<title>測試</title>
<META http-equiv="Content-Type" content="text/html; charset=big5">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body bottomMargin="0" leftMargin="0" topMargin="0" rightMargin="0">
<TABLE cellSpacing="1" cellPadding="1" width="100%" border="1">
<TR><Th>欄0</Th><Th>欄1</Th><Th>欄2</Th></TR>
<TR><Th>列1</Th><TD style="COLOR: yellow; BACKGROUND-COLOR: green">1,1</TD><TD>1,2</TD></TR>
<TR><Th>列2</Th><TD>2,1</TD>
<TD style="FONT-SIZE: 32px; FONT-STYLE: italic; FONT-FAMILY: 'Bauhaus 93'">2,2</TD></TR>
</TABLE>
<p>輸出格式
<a href="Office.aspx?ext=doc&ContentType=application/msword">Word</a>
<a href="Office.aspx?ext=xls&ContentType=application/vnd.ms-excel">Excel</a>
<a href="Office.aspx?ext=ppt&ContentType=application/vnd.ms-powerpoint">PowerPoint</a>
</p>
</body>
</HTML>
在這個範例中,程式碼轉譯區塊 (<% … %>) 以上是ASP.NET的程式碼,以下是純HTML語法文件,挑選兩表格格子輸出為不同的樣式,以利對照比較。以Internet Explorer(以下簡稱IE)網頁瀏覽顯示如圖1。
圖 1 在IE顯示之原始網頁
當點選圖上任一輸出格式時,視IE安全性設定,可能會跳出圖2的對話框,在圖2對話框中,可以明顯看出,這個網頁的檔案類型已經被當成Microsoft PowerPoint文件,並非是當成HTML文件開啟了。
圖 2 檔案下載對話框
若未出現圖2對話框,可能是允許內崁於網頁上。點選圖2開啟按鈕後,依IE安全性設定,可能內崁於網頁或啟動Office軟體單獨開啟,或另存新檔後,直接透過檔案總管點選開啟。單獨開啟如圖3所示,內崁於網頁如圖4所示。
(a)Word
(b)PowerPoint
圖 3 由Office軟體單獨開啟
(a)Excel
(b)PowerPoint
圖 4 Office文件內崁於IE之中
技術說明
細觀原始碼後,原始碼僅在HTML內容類型加入檔名設定及內容類型(ContentType)設定,因此本文介紹的方法將不限於應用在ASP.NET上,亦可應用在ASP、PHP或其他支援此功能設定的網頁平台。而造成IE能判讀為Office文件的原因為內容類型的正確設定,檔名設定是便於使用者儲存檔案後,得以對應的Office軟體開啟,並非絕對必要,比如說將檔名設為Office.htm,仍可以對應的Office軟體開啟,如圖5所示,此外,會在檔案下載對話框內出現警告訊息。若要強制啟用檔案下載對話框,可在呼叫函數SetResponseHeader時,設定bSaveFile為True。而要輸出為Office文件時,則依指定的內容類型來設定,不同Office文件之內容類型如下表:
內容類型
副檔名
Office軟體
application/msword
.doc
Microsoft Word
application/vnd.ms-excel
.xls
Microsoft Excel
application/vnd.ms-powerpoint
.ppt
Microsoft PowerPoint
圖 5 設定為不同格式之附檔名
更進一步
在前述部份,僅利用Office自動開啟HTML檔案的能力,並未針對各軟體設定對應功能,在大部分自動產生Office文件的要求,多半屬於報表或是特定格式的對應,一般來說可能會有制式的樣版檔,此時可先以Office軟體產生樣版檔後,利用關鍵字來替換特定字串,來輸出制式報表,當Office文件編輯完成後,將其另存為HTML或XML檔後,以檔案讀入功能讀入後,並輸出成為文件。
本文以一簡易公文為例來說明,首先先以Word設計一公文樣本,並將其存成XML格式文件,在範本中,欲以程式替換的文字,以關鍵字存於檔案內,本例中,以(key:…)為搜尋替換關鍵字,如圖6所示。
圖 6 公文樣本
依前述觀念開發一個可讀取文字檔並處理的網頁程式,其中Word存成XML檔時,預設格式為UTF-8,因此在讀檔及輸出時,應注意字串的編碼方式轉換。網頁程式範例如下:
<%@ Page Language="vb" AutoEventWireup="false" CodePage="950" %>
<!-- #include virtual = "StrTools.aspx" -->
<!-- #include virtual = "FileTool.aspx" -->
<!-- #include virtual = "ResponseFile.aspx" -->
<script language=vb runat=server id="modCount">
Public Function ResponseWord()
Dim sFile As String = MyGetFullTextFile(Server.MapPath("/Test/Office/公文.xml"), _
enuStandardCodePages.SCP_CP_UTF8)
sFile = Replace(sFile, "(key:受文者)", "網頁程式設計師")
sFile = Replace(sFile, "(key:主旨)", "自動輸出WORD文件說明。請查收。")
sFile = Replace(sFile, "(key:說明)", "本文為說明簡易輸出方式,程式碼說明如附件。")
sFile = Replace(sFile, "(key:正本收文)", "本文閱讀者")
sFile = Replace(sFile, "(key:副本收文)", "鄭子璉")
Dim arrBytes = StringToBytes(sFile, enuStandardCodePages.SCP_CP_UTF8)
ResponseFile(arrBytes, "application/msword", "test.doc")
End Function
</script>
<% ResponseWord() %>
當本網頁執行時,將會詢問使用者Word檔處理方式,如圖7所示。以Word開啟後,可以看到,欲替換的字串已經填入在對應位置,如圖8所示。讀者若需直接輸出Office文件,亦可詳加研讀相關語法後,直接輸出。
圖 7 檔案下載詢問畫面
圖 8 自動填入資料產生公文
小結
本文以簡易的內容類型替換方式,讓網頁程式產生Office文件更容易,也免去複雜的Windows權限設定、DCOM可能耗損Server的記憶體及程序鎖死的情形,網頁程式設計師可依個人需求調整而直接輸出HTML格式或XML格式,因屬純文字格式,使得變更資料內容或依指定格式變更更為容易,且不使用二進位資料,不易發生因DCOM無法正確釋放,而使得系統資源逐漸減少。此外,輸出時採用Office文件副檔名,有助於檔案總管直接開啟,換句話說,本文內容亦可在Windows Form程式下應用,或其他作業系統下產生對應文字檔做資料交換,助於系統整合、政府採購及企業內部電子文件交流。
其他參考資訊:
DCOM元件權限設定:http://tlcheng.twbbs.org/TLCheng/Basic/vbs/dcom/automation.htm
在ASP.NET中動態共用原始碼:http://www.microsoft.com/taiwan/msdn/columns/mvp/aspxcode.htm
公文範例所引用的程式碼:http://tlcheng.twbbs.org/TLCheng/Net/NetList.aspx
作者簡介:
個人網站http://tlcheng.twbbs.org/TLCheng/
任職於水海科技系統研發驗證工作室/國立成功大學水利及海洋工程研究所博士候選人
獲選2003、2004、2005微軟最有價值專家
參與開發國內水資源、防洪等模式並擬定相關法規條文
個人網站中提供Basic/Fortran/輔助說明檔/Windows API/Net相關技術說明及原始碼及專業著作相關文章
<%@ Page Language="vb" AutoEventWireup="false" CodePage=”950" %> <script language="vb" runat="server" id="modOffice"> Public Function SetResponseHeader(Byval sContentType As String, Byval sFileName As String, _ Byval bSaveFile As Boolean) Dim sContentDisposition As String With Response If bSaveFile Then sContentDisposition = "attachment; " ' 強制存檔,未設定則依瀏覽器預設開啟或存檔 End If If Len(sFileName) > 0 Then sContentDisposition = sContentDisposition & "filename=" & sFileName ' 檔名 End If If Len(sContentDisposition) > 0 Then .AddHeader("Content-disposition", sContentDisposition) End If .ContentType = sContentType End With End Function </script> <%If Len(Request.QueryString("ext")) > 0 Then SetResponseHeader(Request.QueryString("ContentType"), "Office." & Request.QueryString("ext"), False) End If%> <HTML> <HEAD> <title>測試</title> <META http-equiv="Content-Type" content="text/html; charset=big5"> <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5"> </HEAD> <body bottomMargin="0" leftMargin="0" topMargin="0" rightMargin="0"> <TABLE cellSpacing="1" cellPadding="1" width="100%" border="1"> <TR><Th>欄0</Th><Th>欄1</Th><Th>欄2</Th></TR> <TR><Th>列1</Th><TD style="COLOR: yellow; BACKGROUND-COLOR: green">1,1</TD><TD>1,2</TD></TR> <TR><Th>列2</Th><TD>2,1</TD> <TD style="FONT-SIZE: 32px; FONT-STYLE: italic; FONT-FAMILY: 'Bauhaus 93'">2,2</TD></TR> </TABLE> <p>輸出格式 <a href="Office.aspx?ext=doc&ContentType=application/msword">Word</a> <a href="Office.aspx?ext=xls&ContentType=application/vnd.ms-excel">Excel</a> <a href="Office.aspx?ext=ppt&ContentType=application/vnd.ms-powerpoint">PowerPoint</a> </p> </body> </HTML> |
圖 1 在IE顯示之原始網頁
圖 2 檔案下載對話框
(a)Word | (b)PowerPoint |
(a)Excel | (b)PowerPoint |
內容類型 | 副檔名 | Office軟體 |
---|---|---|
application/msword | .doc | Microsoft Word |
application/vnd.ms-excel | .xls | Microsoft Excel |
application/vnd.ms-powerpoint | .ppt | Microsoft PowerPoint |
圖 5 設定為不同格式之附檔名
圖 6 公文樣本
<%@ Page Language="vb" AutoEventWireup="false" CodePage="950" %> <!-- #include virtual = "StrTools.aspx" --> <!-- #include virtual = "FileTool.aspx" --> <!-- #include virtual = "ResponseFile.aspx" --> <script language=vb runat=server id="modCount"> Public Function ResponseWord() Dim sFile As String = MyGetFullTextFile(Server.MapPath("/Test/Office/公文.xml"), _ enuStandardCodePages.SCP_CP_UTF8) sFile = Replace(sFile, "(key:受文者)", "網頁程式設計師") sFile = Replace(sFile, "(key:主旨)", "自動輸出WORD文件說明。請查收。") sFile = Replace(sFile, "(key:說明)", "本文為說明簡易輸出方式,程式碼說明如附件。") sFile = Replace(sFile, "(key:正本收文)", "本文閱讀者") sFile = Replace(sFile, "(key:副本收文)", "鄭子璉") Dim arrBytes = StringToBytes(sFile, enuStandardCodePages.SCP_CP_UTF8) ResponseFile(arrBytes, "application/msword", "test.doc") End Function </script> <% ResponseWord() %> |
圖 7 檔案下載詢問畫面
圖 8 自動填入資料產生公文
在ASP.NET中動態共用原始碼:http://www.microsoft.com/taiwan/msdn/columns/mvp/aspxcode.htm
公文範例所引用的程式碼:http://tlcheng.twbbs.org/TLCheng/Net/NetList.aspx
任職於水海科技系統研發驗證工作室/國立成功大學水利及海洋工程研究所博士候選人
獲選2003、2004、2005微軟最有價值專家
參與開發國內水資源、防洪等模式並擬定相關法規條文
個人網站中提供Basic/Fortran/輔助說明檔/Windows API/Net相關技術說明及原始碼及專業著作相關文章