C# 導出HTML為Excel


最近在項目中需要Excel導出,有多個Sheet頁,每個Sheet頁的內容比較多,且不是規整的表格,綁定值是個比較麻煩的事,便考慮直接將HTML轉換為Excel文件進行導出。

一、使用JS方法將HTML導出為Excel

原理就是獲取需要導出到Excel的HTML代碼,然后利用JS方法進行導出。此代碼可以兼容IE8及主流瀏覽器,但是不支持多個Sheet頁的導出,在IE8下也不能自定義Sheet頁的名字。

<li>
<button id="btnExport" class="btn btn-primary" onclick="javascript:HtmlExportToExcel('mainContent')">
                        導出
                    </button>
<a id="dlink" style="display: none;"></a>
                </li>   
//jQuery HTML導出Excel文件(兼容IE及所有瀏覽器)
        function HtmlExportToExcel(tableid) {
            var filename = $('#divTitle').text();
            var sheetName = "已開展工作情況";
            if (getExplorer() == 'ie' || getExplorer() == undefined) {
                HtmlExportToExcelForIE(tableid, filename,sheetName);
            }
            else {
                HtmlExportToExcelForEntire(tableid, filename,sheetName)
            }
        }

        //IE瀏覽器導出Excel
        function HtmlExportToExcelForIE(tableid, filename,sheetName) {
            try {
                var winname = window.open('', '_blank', 'top=10000');
                var strHTML = $("#" + tableid).html();

                winname.document.open('application/vnd.ms-excel', 'export excel');
                winname.document.writeln(strHTML);
                winname.document.execCommand('saveas', '', filename + '.xls');
                winname.close();

            } catch (e) {
                alert(e.description);
            }
        }

        //非IE瀏覽器導出Excel
        var HtmlExportToExcelForEntire = (function () {
            var uri = 'data:application/vnd.ms-excel;base64,',
        template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>',
        base64 = function (s) { return window.btoa(unescape(encodeURIComponent(s))) },
        format = function (s, c) { return s.replace(/{(\w+)}/g, function (m, p) { return c[p]; }) }
            return function (table, name,sheetName) {
                if (!table.nodeType) { table = $("#" + table); }
                var ctx = { worksheet: sheetName || 'Worksheet', table: table.html() };
                document.getElementById("dlink").href = uri + base64(format(template, ctx));
                document.getElementById("dlink").download = name + ".xls";
                document.getElementById("dlink").click();
            }
        })()
        function getExplorer() {
            var explorer = window.navigator.userAgent;
            //ie 
            if (explorer.indexOf("MSIE") >= 0) {
                return 'ie';
            }
                //firefox 
            else if (explorer.indexOf("Firefox") >= 0) {
                return 'Firefox';
            }
                //Chrome
            else if (explorer.indexOf("Chrome") >= 0) {
                return 'Chrome';
            }
                //Opera
            else if (explorer.indexOf("Opera") >= 0) {
                return 'Opera';
            }
                //Safari
            else if (explorer.indexOf("Safari") >= 0) {
                return 'Safari';
            }
        }

另外,由於生成的不是真正的Excel文件,只是把HTML轉換為Excel的文件,會出現如下提示,用戶體驗不好。

二、利用后台方法將HTML導出為Excel

原理與第一種方法類似,也是將HTML代碼導出為Excel,只是改用后台文件流方式,避免了瀏覽器兼容性問題。

由於也是HTML導出為Excel文件,也會出現文件擴展名不一致的提示。

思路是:點擊導出按鈕時,獲取要導出內容的HTML代碼,並放到Hidden控件中,利用Form Post提交方式傳送到后台Action方法,在Action方法中構建Sheet頁的Dictionary,key是SheetName,Value是Sheet的HTML代碼,然后循環Dictionary生成多個Sheet頁,並導出。

<form id="form1" method="post">
        @Html.Hidden("tbBMXXHTML")
        @Html.Hidden("tbBMXXTitle")
        @Html.Hidden("FileTitle")
    </form> ------------- <li> <button id="btnExport" class="btn btn-primary" type="submit" onclick="ExportExcel()" > 導出 </button> </li>
//導出Excel
        function ExportExcel() {
            var URL = '@Url.Action("GreenCarSummaryExport", "GreenCar", new { area = "GreenCar" })';
            var FileTitle = $("#divTitle").text();
            $("#FileTitle").val(FileTitle);

            $("#tbBMXXHTML").val(encodeURI($("#tbBMXX").html()));
            $("#tbBMXXTitle").val("已開展工作情況");

            window.form1.action = URL;
            window.form1.submit();
        }
        public void GreenCarSummaryExport(FormCollection collection)
        {
            string tbBMXXHTML = HttpUtility.UrlDecode(collection["tbBMXXHTML"]);
            string tbBMXXTitle = collection["tbBMXXTitle"];
            string FileTitle = collection["FileTitle"];

            Dictionary<string, string> dicSheet = new Dictionary<string, string>();
            dicSheet.Add(tbBMXXTitle, tbBMXXHTML);

            //把HTML轉換為Excel
            HTMLToExcelHelper.ExportHTMLToExcel(dicSheet, FileTitle);
        }
/// <summary>
        /// 導出HTML為Excel文件
        /// </summary>
        /// <param name="dicSheet">導出內容:key是SheetName,Value是HTML代碼</param>
        /// <param name="fileTitle">文件名</param>
        public static void ExportHTMLToExcel(Dictionary<string, string> dicSheet, string fileTitle)
        {
            StringBuilder sbBody = new StringBuilder();
            StringBuilder sbSheet = new StringBuilder();

            //定義Excel頭部
            sbBody.AppendFormat(
                "MIME-Version: 1.0\r\n" +
                "X-Document-Type: Workbook\r\n" +
                "Content-Type: multipart/related; boundary=\"-=BOUNDARY_EXCEL\"\r\n\r\n" +
                "---=BOUNDARY_EXCEL\r\n" +
                "Content-Type: text/html; charset=\"gb2312\"\r\n\r\n" +
                "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n" +
                "xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n\r\n" +
                "<head>\r\n" +
                "<xml>\r\n" +
                "<x:ExcelWorkbook>\r\n" +
                "<x:ExcelWorksheets>\r\n");

            //定義Sheet
            foreach (KeyValuePair<string, string> kv in dicSheet)
            {
                string gid = Guid.NewGuid().ToString();
                sbBody.AppendFormat("<x:ExcelWorksheet>\r\n" +
                    "<x:Name>{0}</x:Name>\r\n" +
                    "<x:WorksheetSource HRef=\"cid:{1}\"/>\r\n" +
                    "</x:ExcelWorksheet>\r\n"
                    , kv.Key
                    , gid);

                sbSheet.AppendFormat(
                     "---=BOUNDARY_EXCEL\r\n" +
                     "Content-ID: {0}\r\n" +
                     "Content-Type: text/html; charset=\"gb2312\"\r\n\r\n" +
                     "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n" +
                     "xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n\r\n" +
                     "<head>\r\n" +
                     "<xml>\r\n" +
                     "<x:WorksheetOptions>\r\n" +
                     "<x:ProtectContents>False</x:ProtectContents>\r\n" +
                     "<x:ProtectObjects>False</x:ProtectObjects>\r\n" +
                     "<x:ProtectScenarios>False</x:ProtectScenarios>\r\n" +
                     "</x:WorksheetOptions>\r\n" +
                     "</xml>\r\n" +
                     "</head>\r\n" +
                     "<body>\r\n"
                     , gid);

                sbSheet.Append("<table border='1'>");
                sbSheet.Append(kv.Value);
                sbSheet.Append("</table>");
                sbSheet.Append("</body>\r\n" +
                    "</html>\r\n\r\n");
            }

            //定義Excel尾部
            StringBuilder sb = new StringBuilder(sbBody.ToString());
            sb.Append("</x:ExcelWorksheets>\r\n" +
                "</x:ExcelWorkbook>\r\n" +
               "</xml>\r\n" +
                "</head>\r\n" +
                "</html>\r\n\r\n");
            sb.Append(sbSheet.ToString());
            sb.Append("---=BOUNDARY_EXCEL--");

            //導出文件
            HttpContext.Current.Response.Clear();
            HttpContext.Current.Response.ClearContent();
            HttpContext.Current.Response.ClearHeaders();
            HttpContext.Current.Response.Buffer = true;
            bool isFireFox = false;
            if (HttpContext.Current.Request.ServerVariables["http_user_agent"].ToLower().IndexOf("firefox") != -1)
            {
                isFireFox = true;
            }
            if (isFireFox)
            {
                HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + fileTitle + ".xls");
            }
            else
            {
                HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(System.Text.Encoding.UTF8.GetBytes(fileTitle)) + ".xls");
            }
            HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
            HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("gb2312");
            HttpContext.Current.Response.Write(sb.ToString());
            HttpContext.Current.Response.End();
        }
View Code

三、利用第三方插件導出

比如利用NPOI,Aspose,ExcelReport等,需要從數據庫重新獲取數據並綁定


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM