28

How can I convert multiple html tables to an excel sheet with multiple worksheets? Could you please help into this.

My example https://jsfiddle.net/kdkd/5p22gdag/

        function tablesToExcel() {
        {

            var tab_text = "<table border='2px'><tr bgcolor='#87AFC6'>";
            var textRange; var j = 0;
            tab = document.getElementById('tbl2'); // id of table


            for (j = 0 ; j < tab.rows.length ; j++) {
                tab_text = tab_text + tab.rows[j].innerHTML + "</tr>";
                //tab_text=tab_text+"</tr>";
            }

            tab_text = tab_text + "</table>";
            var ua = window.navigator.userAgent;
            var msie = ua.indexOf("MSIE ");

            if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))      // If Internet Explorer
            {
                txtArea1.document.open("txt/html", "replace");
                txtArea1.document.write(tab_text);
                txtArea1.document.close();
                txtArea1.focus();
                sa = txtArea1.document.execCommand("SaveAs", true, "Say Thanks to Sumit.xls");
            }
            else                 //other browser not tested on IE 11
                sa = window.open('data:application/vnd.ms-excel,' + encodeURIComponent(tab_text));


            return (sa);
        }

 }
Toby Allen
  • 10,997
  • 11
  • 73
  • 124
KD.
  • 283
  • 1
  • 4
  • 9
  • Have you checked these questions: http://stackoverflow.com/questions/24636956/how-do-i-export-multiple-html-tables-to-excel and http://stackoverflow.com/questions/18234448/exporting-html-tables-to-excel-xls-in-a-separate-sheet? they seem to have solutions for this – Alvaro Montoro Apr 17 '15 at 12:59
  • Thanks for that. I have checked above given link. One little issue is all HTML table has inserted into one worksheet. ( Multiple worksheet successfully created ) but, – KD. Apr 18 '15 at 05:56
  • Here is example what you want..http://jsfiddle.net/qxLn3h86/ – Butani Vijay Apr 18 '15 at 12:24
  • I have tried this but my table has inline CSS so its not working. Please check this fiddle http://jsfiddle.net/kdkd/qxLn3h86/49/ – KD. Apr 18 '15 at 12:51
  • awaiting for solution.. Please help – KD. Apr 21 '15 at 11:48

8 Answers8

40

You can do as below : Here is Full Example

Html :

<table id="tbl1" class="table2excel">
        <tr>
            <td>Product</td>
            <td>Price</td>
            <td>Available</td>
            <td>Count</td>
        </tr>
        <tr>
            <td>Bred</td>
            <td>1</td>
            <td>2</td>
             <td>3</td>
        </tr>
        <tr>
            <td>Butter</td>
            <td>4   </td>
            <td>5   </td>
            <td >6  </td>
        </tr>
  </table>
<hr>

  <table id="tbl2" class="table2excel">
        <tr>
            <td>Product</td>
            <td>Price</td>
            <td>Available</td>
            <td>Count</td>
        </tr>
        <tr>
            <td>Bred</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
        </tr>
        <tr>
            <td>Butter</td>
            <td>14</td>
            <td>15</td>
            <td >16</td>
        </tr>
    </table>


<button  onclick="tablesToExcel(['tbl1','tbl2'], ['ProductDay1','ProductDay2'], 'TestBook.xls', 'Excel')">Export to Excel</button>

Javascript:

 var tablesToExcel = (function() {
    var uri = 'data:application/vnd.ms-excel;base64,'
    , tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
      + '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
      + '<Styles>'
      + '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
      + '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
      + '</Styles>' 
      + '{worksheets}</Workbook>'
    , tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>'
    , tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>'
    , 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(tables, wsnames, wbname, appname) {
      var ctx = "";
      var workbookXML = "";
      var worksheetsXML = "";
      var rowsXML = "";

      for (var i = 0; i < tables.length; i++) {
        if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
        for (var j = 0; j < tables[i].rows.length; j++) {
          rowsXML += '<Row>'
          for (var k = 0; k < tables[i].rows[j].cells.length; k++) {
            var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
            var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
            var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
            dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerHTML;
            var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
            dataFormula = (dataFormula)?dataFormula:(appname=='Calc' && dataType=='DateTime')?dataValue:null;
            ctx = {  attributeStyleID: (dataStyle=='Currency' || dataStyle=='Date')?' ss:StyleID="'+dataStyle+'"':''
                   , nameType: (dataType=='Number' || dataType=='DateTime' || dataType=='Boolean' || dataType=='Error')?dataType:'String'
                   , data: (dataFormula)?'':dataValue
                   , attributeFormula: (dataFormula)?' ss:Formula="'+dataFormula+'"':''
                  };
            rowsXML += format(tmplCellXML, ctx);
          }
          rowsXML += '</Row>'
        }
        ctx = {rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i};
        worksheetsXML += format(tmplWorksheetXML, ctx);
        rowsXML = "";
      }

      ctx = {created: (new Date()).getTime(), worksheets: worksheetsXML};
      workbookXML = format(tmplWorkbookXML, ctx);



      var link = document.createElement("A");
      link.href = uri + base64(workbookXML);
      link.download = wbname || 'Workbook.xls';
      link.target = '_blank';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  })();
Butani Vijay
  • 4,181
  • 2
  • 29
  • 61
  • 4
    this is pure genius! :-) – Maciej Jankowski Apr 18 '15 at 13:55
  • I have tried this but my table has inline CSS so its not working. Please check this fiddle http://jsfiddle.net/kdkd/qxLn3h86/49/ – KD. Apr 19 '15 at 10:24
  • This link may be help you .http://stackoverflow.com/questions/18467418/retain-html-table-styling-after-exporting-to-excel-using-javascript-jquery – Butani Vijay Apr 20 '15 at 04:28
  • 1
    Thats file but both code are different, One is for create multiple worksheet and another is for with CSS.. How can i merge ??? – KD. Apr 20 '15 at 07:33
  • phheww, Not getting solution for the same. Please help – KD. Apr 21 '15 at 11:48
  • This is substantially my code from here http://stackoverflow.com/questions/26301811/adding-worksheet-to-the-excel-file-using-javascript/26323012#26323012. And no, this will not work with CSS because it is XML and not HTML. If you look at my example, you will see that I use `data-style` attributes to define styles which then correspond with `Style` elements in the XML. All styles must be defined in such `Style` elements. – Axel Richter Apr 23 '15 at 11:53
  • I don't know of who is this code, because this code is repeat in this post http://stackoverflow.com/questions/26301811/adding-worksheet-to-the-excel-file-using-javascript/26323012#26323012. I copy this same code into a xhtml (JSF 2.2) and I get the next error "The processing instruction target matching "[xX][mM][lL]" is not allowed.". I looked on internet, but I didn't find the solution. If anyone could help me, I will be grateful – – Ignacio Chiazzo Oct 27 '15 at 01:10
  • I've picked this version and took it from here, to make a better version. Most of it is working fine. but I really had to do some heavy changes, including adding some styles. Also, this code blindly trusts whatever input is fed. It is so underperformant. You should save those `tables[i].rows[j].cells[k]` in a variable. Also, storings the length of the pieces in a variable will ease the processing time. I've, so far, made it run in less than 200ms for 2 tables, with over 700 cells. – Ismael Miguel Apr 14 '16 at 10:25
  • 1
    This answer is not working in IE 11. Is there any alternative solution for make it work on IE ? Thanks in advance – BOBIN JOSEPH Jul 11 '16 at 14:16
  • @ButaniVijay thanks for posting the solution. The code snippet works perfect until the number of rows, in my experiment, exceeds 3407 rows with Chrome. The browser simply complains 'Failed - Network error'. However, Firefox works fine. – Stone Nov 07 '16 at 18:47
  • Thank You so much, this solution worked for me. Only I have replaced with and removed this line : – Madhura May 03 '17 at 07:29
  • CSS is not getting applied in excel. can you please suggest change in above coding so that table can export with CSS? – Madhura May 03 '17 at 09:12
  • Above code is working on Mozilla and chrome but not working on IE. – Madhura May 03 '17 at 09:29
  • This works only if the table is in the same format as you showed in the fiddle example. If i give a tab or more space inside tag then it corrupts the format in excel.. – Prasanth Jaya Aug 21 '17 at 06:23
  • what is the XLS version of this format? I want to write more – brauliobo Dec 22 '22 at 16:53
7

Here is a better solution that supports exporting table in the latest Excel format i.e. xlsx . The accepted solution would fail in case the total number of rows being exported exceeds 3407 on Chrome.

An example from the link above: http://jsfiddle.net/6ckj281f/

html

<button onclick="saveFile()">Save XLSX file</button>

javascript

window.saveFile = function saveFile () {
var data1 = [{a:1,b:10},{a:2,b:20}];
var data2 = [{a:100,b:10},{a:200,b:20}];
var opts = [{sheetid:'One',header:true},{sheetid:'Two',header:false}];
var res = alasql('SELECT INTO XLSX("restest344b.xlsx",?) FROM ?',
                 [opts,[data1,data2]]);
}
Stone
  • 1,119
  • 9
  • 17
5

Did not find anything on the internet to fix this, so I created my own. This is a working example that creates 2 or more sheets (1 sheet per table) and WORKS PROPERLY. Enjoy! :)

Run the example in https://jsfiddle.net/xvkt0yw9/

This is a ~reverse-engineering of .mht representation of XLS export (Web page). The sheet name is defined in the data-SheetName attribute of each table. The function can be easily transposed to other programming languages. (It is basically full of replace mes)

Also provided inline-style for cell number formating (As text, General, 2 decimal)

Note: the cell grid does show regardless of whether you set the option or not... Warning Do not indent the javascript function. (i don't know what happens to the XLS if you do, did not test, did not have to) Html: (Put the following content inside a test.html file and run it in your browser. Click on the button and open the exported Worksheet.xls)

<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script type="text/javascript">
var tablesToExcel = (function ($) {
    var uri = 'data:application/vnd.ms-excel;base64,'
    , html_start = `<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">`
    , template_ExcelWorksheet = `<x:ExcelWorksheet><x:Name>{SheetName}</x:Name><x:WorksheetSource HRef="sheet{SheetIndex}.htm"/></x:ExcelWorksheet>`
    , template_ListWorksheet = `<o:File HRef="sheet{SheetIndex}.htm"/>`
    , template_HTMLWorksheet = `
------=_NextPart_dummy
Content-Location: sheet{SheetIndex}.htm
Content-Type: text/html; charset=windows-1252

` + html_start + `
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
    <link id="Main-File" rel="Main-File" href="../WorkBook.htm">
    <link rel="File-List" href="filelist.xml">
</head>
<body><table>{SheetContent}</table></body>
</html>`
    , template_WorkBook = `MIME-Version: 1.0
X-Document-Type: Workbook
Content-Type: multipart/related; boundary="----=_NextPart_dummy"

------=_NextPart_dummy
Content-Location: WorkBook.htm
Content-Type: text/html; charset=windows-1252

` + html_start + `
<head>
<meta name="Excel Workbook Frameset">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<link rel="File-List" href="filelist.xml">
<!--[if gte mso 9]><xml>
 <x:ExcelWorkbook>
    <x:ExcelWorksheets>{ExcelWorksheets}</x:ExcelWorksheets>
    <x:ActiveSheet>0</x:ActiveSheet>
 </x:ExcelWorkbook>
</xml><![endif]-->
</head>
<frameset>
    <frame src="sheet0.htm" name="frSheet">
    <noframes><body><p>This page uses frames, but your browser does not support them.</p></body></noframes>
</frameset>
</html>
{HTMLWorksheets}
Content-Location: filelist.xml
Content-Type: text/xml; charset="utf-8"

<xml xmlns:o="urn:schemas-microsoft-com:office:office">
    <o:MainFile HRef="../WorkBook.htm"/>
    {ListWorksheets}
    <o:File HRef="filelist.xml"/>
</xml>
------=_NextPart_dummy--
`
    , 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 (tables, filename) {
        var context_WorkBook = {
            ExcelWorksheets:''
        ,   HTMLWorksheets: ''
        ,   ListWorksheets: ''
        };
        var tables = jQuery(tables);
        $.each(tables,function(SheetIndex){
            var $table = $(this);
            var SheetName = $table.attr('data-SheetName');
            if($.trim(SheetName) === ''){
                SheetName = 'Sheet' + SheetIndex;
            }
            context_WorkBook.ExcelWorksheets += format(template_ExcelWorksheet, {
                SheetIndex: SheetIndex
            ,   SheetName: SheetName
            });
            context_WorkBook.HTMLWorksheets += format(template_HTMLWorksheet, {
                SheetIndex: SheetIndex
            ,   SheetContent: $table.html()
            });
            context_WorkBook.ListWorksheets += format(template_ListWorksheet, {
                SheetIndex: SheetIndex
            });
        });

        var link = document.createElement("A");
        link.href = uri + base64(format(template_WorkBook, context_WorkBook));
        link.download = filename || 'Workbook.xls';
        link.target = '_blank';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
})(jQuery);
</script>
</head>
<body>
    <button onclick="tablesToExcel('#table_1,#table_2', 'WorkSheet.xls');">HTML Tables to XLS sheets</button>
    <table id="table_1" data-SheetName="My custom sheet 1">
        <thead>
            <tr >
                <td colspan="4" style="border-color:#fff;">
                    Left info
                </td>
                <td colspan="3" class="text-right" style="border-color:#fff;">
                    Right info
                </td>
            </tr>
            <tr>
                <th colspan="7" style="border-color:#fff;text-decoration:underline;font-size:2em;" class="text-center">
                    Title
                </th>
            </tr>
            <tr>
                <th colspan="7" style="border-left-color:#fff; border-right-color:#fff;border-top-color:#fff;text-decoration:underline;font-size:1.5em;" class="text-center">
                    Subtitle
                </th>
            </tr>
            <tr>
                <th colspan="7" style="border-left-color:#fff;border-right-color:#fff;border-top-color:#fff;height:50px;">
                    Spacer
                </th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td style="mso-number-format:'\@'">1</td>
                <td style="mso-number-format:'General'">2</td>
                <td style="mso-number-format:'0\.00'">3</td>
                <td>info</td>
                <td>info</td>
                <td>info</td>
                <td>info</td>
            </tr>
        </tbody>
    </table>
    <table id="table_2" data-SheetName="My custom worksheet 2">
        <thead>
            <tr >
                <td colspan="2" style="border-color:#fff;">
                    Left info 2
                </td>
                <td colspan="2" class="text-right" style="border-color:#fff;">
                    Right info 2
                </td>
            </tr>
            <tr>
                <th colspan="4" style="border-color:#fff;text-decoration:underline;font-size:2em;" class="text-center">
                    Title 2
                </th>
            </tr>
            <tr>
                <th colspan="4" style="border-left-color:#fff; border-right-color:#fff;border-top-color:#fff;text-decoration:underline;font-size:1.5em;" class="text-center">
                    Subtitle 2
                </th>
            </tr>
            <tr>
                <th colspan="4" style="border-left-color:#fff;border-right-color:#fff;border-top-color:#fff;height:50px;">
                    Spacer 2
                </th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td style="mso-number-format:'\@'">3</td>
                <td style="mso-number-format:'General'">4</td>
                <td style="mso-number-format:'0\.00'">5</td>
                <td>info2</td>
                <td>info3</td>
                <td>info4</td>
                <td>info5</td>
            </tr>
        </tbody>
    </table>
</body>
</html>
thundorstorm
  • 99
  • 1
  • 2
1

Bhutani Vijay's code works perfectly fine. For IE 11 compatibility I used the Blob object as below:

var tablesToExcel = (function() {
  var uri = 'data:application/vnd.ms-excel;base64,',
    tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">' +
    '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>' +
    '<Styles>' +
    '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>' +
    '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>' +
    '</Styles>' +
    '{worksheets}</Workbook>',
    tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>',
    tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>',
    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(tables, wsnames, wbname, appname) {
    var ctx = "";
    var workbookXML = "";
    var worksheetsXML = "";
    var rowsXML = "";

    for (var i = 0; i < tables.length; i++) {
      if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
      for (var j = 0; j < tables[i].rows.length; j++) {
        rowsXML += '<Row>'
        for (var k = 0; k < tables[i].rows[j].cells.length; k++) {
          var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
          var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
          var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
          dataValue = (dataValue) ? dataValue : tables[i].rows[j].cells[k].innerHTML;
          var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
          dataFormula = (dataFormula) ? dataFormula : (appname == 'Calc' && dataType == 'DateTime') ? dataValue : null;
          ctx = {
            attributeStyleID: (dataStyle == 'Currency' || dataStyle == 'Date') ? ' ss:StyleID="' + dataStyle + '"' : '',
            nameType: (dataType == 'Number' || dataType == 'DateTime' || dataType == 'Boolean' || dataType == 'Error') ? dataType : 'String',
            data: (dataFormula) ? '' : dataValue,
            attributeFormula: (dataFormula) ? ' ss:Formula="' + dataFormula + '"' : ''
          };
          rowsXML += format(tmplCellXML, ctx);
        }
        rowsXML += '</Row>'
      }
      ctx = {
        rows: rowsXML,
        nameWS: wsnames[i] || 'Sheet' + i
      };
      worksheetsXML += format(tmplWorksheetXML, ctx);
      rowsXML = "";
    }

    ctx = {
      created: (new Date()).getTime(),
      worksheets: worksheetsXML
    };
    workbookXML = format(tmplWorkbookXML, ctx);

    var link = document.createElement("A");
    
    // IE 11
    if (window.navigator.msSaveBlob) {
      var blob = new Blob([workbookXML], {
        type: "application/csv;charset=utf-8;"
      });
      navigator.msSaveBlob(blob, 'test.xls');
    }
    // Chrome and other browsers
    else {
      link.href = uri + base64(workbookXML);
    }

    link.download = wbname || 'Workbook.xls';
    link.target = '_blank';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }
})();
Ninja
  • 57
  • 1
  • 11
0

Use Below code for multiple sheets. I am using three tables data for generating excel. Import library:

import * as XLSX from "xlsx";

static doExcel1(tableId1, tableId2, tableId3) {

    let targetTableElm1 = document.getElementById(tableId1);
    let targetTableElm2 = document.getElementById(tableId2);
    let targetTableElm3 = document.getElementById(tableId3);

    const wb = { SheetNames: [], Sheets: {} };
    var ws1 = XLSX.utils.table_to_book(targetTableElm1).Sheets.Sheet1;
    wb.SheetNames.push("Sheet1"); wb.Sheets["Sheet1"] = ws1;

    var ws2 = XLSX.utils.table_to_book(targetTableElm2).Sheets.Sheet1;
    wb.SheetNames.push("Sheet2"); wb.Sheets["Sheet2"] = ws2;

    var ws3 = XLSX.utils.table_to_book(targetTableElm3).Sheets.Sheet1;
    wb.SheetNames.push("Sheet3"); wb.Sheets["Sheet3"] = ws3;
    console.log(ws1); console.log(ws2); console.log(ws3); console.log(wb);
    const blob = new Blob([this.s2ab(XLSX.write(wb, { bookType: 'xlsx', type: 'binary' }))], {
      type: "application/octet-stream"
    });
    const link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = 'demo.xlsx';

    document.body.appendChild(link);

    link.click();

    document.body.removeChild(link);
  }
  static s2ab(s) {
    const buf = new ArrayBuffer(s.length);
    const view = new Uint8Array(buf);
    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    return buf;
  }

Call using table ids: doExcel1("ExampleTable1","ExampleTable2","ExampleTable3"); on click of button.

NOTE: Above solution is only for angular if you want use it in node or js then you need to some changes.

0

@Butani Vijay

I found one issue with your code. Though maybe you could argue maybe my source table is not strictly HTML compliant.
Specifically my table is defined similar to

    <table id="tbl1">
                                    <thead>
                                        <tr>
                                            <th>Name</th>
                                            <th>E-Mail</th>
                                            <th>Last<br>Login</th>
                                            <th>Suspended</th>
                                        </tr>
                                    </thead>
                                    <tbody>

                                            <tr>
                                                <td><a target="_new" href="https://xxxxx.zendesk.com/agent/users/378955944453">Joe User</a></td>
                                                <td>JUser@xyz.edu</td>
                                                <td>2020-02-18T16:42:50Z</td>
                                                <td>false</td>
                                            </tr>
                                        <tfoot>
                                                <tr>
                                                    <td><b>Totals: </b></td>
                                                    <td></td>
                                                    <td></td>
                                                    <td></td>
                                                </tr>
                                        </tfoot>
                                    </tbody>

    </table>

and because of the <br> included in <th>Last<br>Login</th> the XML parse indicates it expected a </br>. But why ??? HTML doesnt really have a </br> And because of this although XLS would open there was no data in the spreadsheet, nor were any worksheets defined

But a suitable fix is to change in your javascript of

dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerHTML;

to

dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerText;
dana c
  • 1
  • You can't address another answer in your answer. If you found a problem in an existing answer you should post full answer of your own. – Dharman Mar 21 '20 at 21:02
0

I just posted this to give one more option to export in multiple sheet with css. Working Fiddle

I strucked for more days and found this ways.Hope this may helps for other.

$('button').click(function() {
tablesToExcel(['tbl1','tbl2'], ['ProductDay1','ProductDay2'], 'TestBook.xls', 'Excel')

});  
  
  var tablesToExcel = (function() {
    var uri = 'data:application/vnd.ms-excel;base64,'
    , tmplWorkbookXML = '<?xml version="1.0" encoding="windows-1252"?><?mso-application progid="Excel.Sheet"?>'
      + '   <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel"  xmlns:html="http://www.w3.org/TR/REC-html40">'
    + '     <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">'
      + '           <Author>Qompare</Author>'
      + '           <Created>{created}</Created>'
      + '       </DocumentProperties>'
    + '     <Styles>'
      + '           <Style ss:ID="Default" ss:Name="Normal">'
      + '               <NumberFormat ss:Format=""/>'
      + '           </Style>'
      + '           <Style ss:ID="Header">'
      + '               <Alignment ss:Vertical="Bottom"/>'
    + '             <Borders>'
      + '                   <Border ss:Color="#000000" ss:Weight="2" ss:LineStyle="Continuous" ss:Position="Right"/>'
      + '                   <Border ss:Color="#000000" ss:Weight="2" ss:LineStyle="Continuous" ss:Position="Left"/>'
      + '                   <Border ss:Color="#000000" ss:Weight="2" ss:LineStyle="Continuous" ss:Position="Top"/>'
      + '                   <Border ss:Color="#000000" ss:Weight="2" ss:LineStyle="Continuous" ss:Position="Bottom"/>'
    + '             </Borders>'
      + '               <Font ss:FontName="Calibri" ss:Size="12" ss:Color="#000000"/>'
      + '               <Interior ss:Color="#cccccc" ss:Pattern="Solid" />'
      + '               <NumberFormat/>'
      + '               <Protection/>'
      + '           </Style>'
    + '         <Style ss:ID="Changed">'
      + '               <Borders/>'
      + '               <Font ss:Color="#ff0000"></Font>'
      + '               <Interior ss:Color="#99CC00" ss:Pattern="Solid"></Interior>'
      + '               <NumberFormat/>'
      + '               <Protection/>'
      + '           </Style>'
    + '         <Style ss:ID="Missed">'
      + '               <Borders/>'
      + '               <Font ss:Color="#ff0000"></Font>'
      + '               <Interior ss:Color="#ff0000" ss:Pattern="Solid"></Interior>'
      + '               <NumberFormat/>'
      + '               <Protection/>'
      + '           </Style>'
    + '         <Style ss:ID="Decimals">'
      + '               <NumberFormat ss:Format="Fixed"/>'
      + '           </Style>'    
    + ' </Styles>' 
    + ' {worksheets}'
      + '</Workbook>'
    , tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}">'
      + '   <ss:Table>'
      + '       {rows}'
      + '   </ss:Table>'
      + '</Worksheet>'
    , tmplCellXML = '           <ss:Cell{attributeStyleID}{attributeFormula}>'
      + '               <ss:Data ss:Type="{nameType}">{data}</ss:Data>'
      + '           </ss:Cell>'
    , 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(tables, wsnames, wbname, appname) {
      var ctx = "";
      var workbookXML = "";
      var worksheetsXML = "";
      var rowsXML = "";

      for (var i = 0; i < tables.length; i++) {
        if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
        for (var j = 0; j < tables[i].rows.length; j++) {
          rowsXML += '      <ss:Row>'
          for (var k = 0; k < tables[i].rows[j].cells.length; k++) {
            var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
            var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
            var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
            dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerHTML;
            if(!isNaN(dataValue)){
                    dataType = 'Number';
                    dataValue = parseFloat(dataValue);
            }
            var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
            dataFormula = (dataFormula)?dataFormula:(appname=='Calc' && dataType=='DateTime')?dataValue:null;
            ctx = {  attributeStyleID: (dataStyle=='Changed' || dataStyle=='Missed'|| dataStyle=='Header')?' ss:StyleID="'+dataStyle+'"':''
                   , nameType: (dataType=='Number' || dataType=='DateTime' || dataType=='Boolean' || dataType=='Error')?dataType:'String'
                   , data: (dataFormula)?'':dataValue
                   , attributeFormula: (dataFormula)?' ss:Formula="'+dataFormula+'"':''
                  };
            rowsXML += format(tmplCellXML, ctx);
          }
          rowsXML += '      </ss:Row>'
        }
        ctx = {rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i};
        worksheetsXML += format(tmplWorksheetXML, ctx);
        rowsXML = "";
      }

      ctx = {created: (new Date()).getTime(), worksheets: worksheetsXML};
      workbookXML = format(tmplWorkbookXML, ctx);
      var link = document.createElement("A");
      link.href = uri + base64(workbookXML);
      link.download = wbname || 'Workbook.xls';
      link.target = '_blank';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }
  })();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

 <!--<button  onclick="tablesToExcel( [{ 'sheet': 'firstsheet','tables' : ['tbl1','tbl2']},{ 'sheet': 'secondsheet','tables' : ['tbl5']}], 'TestBook.xls', 'Excel')">Export to Excel</button> -->
 <!-- button  onclick="">Export to Excel</button> -->
  <button  >Export to Excel</button>
 
<table id="tbl1" class="table2excel">
     <thead>
                    <tr>
                     
                        <th data-style="Header">Product</th>
                        <th data-style="Header">Price</th>
                        <th data-style="Header">Available</th>
                        <th data-style="Header">Count</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr>
                        <td data-style="Changed">Bred</td>
                        <td data-style="Missed">1
</td>
                        <td>037.57834600204239857
</td>
                        <td data-style="Header">3
</td>
                    </tr>
                    <tr>
                        <td>Butter</td>
                        <td>4
</td>
                        <td>5
</td>
                        <td >6
</td>
                    </tr>
                    </tbody>
                </table>
<hr>
  
  <table id="tbl2" class="table2excel">
  <thead>
                    <tr>
                        <th>Product</th>
                        <th>Price</th>
                        <th>Available</th>
                        <th>Count</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr>
                        <td>Bred</td>
                        <td>7.5
</td>
                        <td>8
</td>
                        <td>9
</td>
                    </tr>
                    <tr>
                        <td>Butter</td>
                        <td>14
</td>
                        <td>15
</td>
                        <td >16
</td>
                    </tr>
                    </tbody>
                </table>

<table id="joined" class="table2excel">
  <thead>
    <tr></tr>
    </thead>
      <tbody>
      </tbody>
</table>
user3386779
  • 6,883
  • 20
  • 66
  • 134
-1
function tablesToExcel() {
        {

            var tab_text = document.getElementById("MsoNormalTable").outerHTML;
            var textRange; var j = 0;
            var tab = document.getElementById('MsoNormalTable'); // id of table
            var sa;

            var ua = window.navigator.userAgent;
            var msie = ua.indexOf("MSIE ");
            var txt = document.getElementById('txtArea1').contentWindow;
            if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))      // If Internet Explorer
            {
                txt.document.open("txt/html", "replace");
                txt.document.write(tab_text);
                txt.document.close();
                txt.focus();
                sa = txt.document.execCommand("SaveAs", true, "Say Thanks to Sumit.xls");
            }
            else                 //other browser not tested on IE 11
                sa = window.open('data:application/vnd.ms-excel,' + encodeURIComponent(tab_text));

            return (sa);
        }
 }

<iframe id="txtArea1" style="display:none"></iframe>

It is working with IE7+ fine... :)

Amar Kamthe
  • 2,524
  • 2
  • 15
  • 24