0

I'm a newbie to the field of javascript/angularJS, so please bear with me.I need a way to convert .xls/.xlsx files into .zip files by using jsZip library. I'm making use of alasql for generating the .xls file. I've looked all over for any possible solutions to create zip file of all xls files, but haven't come across any demo. (.txt and .doc files generate just fine, but .xls files does not open if jsZip is used). Any help would be appreciated!!

What I need is an xls file to be generated dynamically, and the same file to be compressed as zip

EDIT :- Here's some of the code which I tried (but with no success)

 var newExcelData = {'Name':'abc'};
        //var res = alasql("SELECT * INTO XLSX('Summary.xlsx',{headers:true}) FROM ? ", [newExcelData]);

        var zip = new JSZip();

        zip.file(alasql("SELECT * INTO XLSX('Summary.xlsx',{headers:true}) FROM ? ", [newExcelData]));
        zip.generateAsync({ type: "blob" })
        .then(function (content) {
            saveAs(content, "example.zip");
        });

PS:- I'm able to make it work in case of generating .xls file.

Please refer below code:-

var newExcelData = {'Name':'abc', 'Age':'12'};

            var zip = new JSZip();

            zip.file("test.xls", [newExcelData]);
            zip.generateAsync({ type: "blob" })
            .then(function (content) {
                saveAs(content, "example.zip");
            });

But although excel sheet is generated, on opening excel sheet is blank. Please help!!

Hi, here's an update :-

I've tried to make use of js-xlsx library - https://github.com/SheetJS/js-xlsx - to generate xls file and then zip it. Please refer the below code..

  function Create_Zip() {

        function datenum(v, date1904) {
            if (date1904) v += 1462;
            var epoch = Date.parse(v);
            return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
        }

        function sheet_from_array_of_arrays(data, opts) {
            var ws = {};
            var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } };
            for (var R = 0; R != data.length; ++R) {
                for (var C = 0; C != data[R].length; ++C) {
                    if (range.s.r > R) range.s.r = R;
                    if (range.s.c > C) range.s.c = C;
                    if (range.e.r < R) range.e.r = R;
                    if (range.e.c < C) range.e.c = C;
                    var cell = { v: data[R][C] };
                    if (cell.v === null) continue;
                    var cell_ref = XLSX.utils.encode_cell({ c: C, r: R });

                    if (typeof cell.v === 'number') cell.t = 'n';
                    else if (typeof cell.v === 'boolean') cell.t = 'b';
                    else if (cell.v instanceof Date) {
                        cell.t = 'n'; cell.z = XLSX.SSF._table[14];
                        cell.v = datenum(cell.v);
                    }
                    else cell.t = 's';

                    ws[cell_ref] = cell;
                }
            }
            if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
            return ws;
        }


        var data = [[1, 2, 3], [true, false, null, "sheetjs"], ["foo", "bar", new Date("2014-02-19T14:30Z"), "0.3"], ["baz", null, "qux"]];
        var ws_name = "SheetJS";

        function Workbook() {
            if (!(this instanceof Workbook)) return new Workbook();
            this.SheetNames = [];
            this.Sheets = {};
        }

        var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);

        /* add worksheet to workbook */
        wb.SheetNames.push(ws_name);
        wb.Sheets[ws_name] = ws;
        var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'binary' });

        function s2ab(s) {
            var buf = new ArrayBuffer(s.length);
            var view = new Uint8Array(buf);
            for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
            return buf;
        }

        var jsonse = JSON.stringify([s2ab(wbout)]);
        var testblob = new Blob([jsonse], { type: "application/json" });
        console.log(testblob);


        var zip = new JSZip();

        zip.file("trial.xls", testblob);

        var downloadFile = zip.generateAsync({ type: "blob" });
        saveAs(downloadFile, 'test.zip');

}

But, the problem here is that I keep getting this error: 'The data of 'trial.xls' is in an unsupported format !' in the console :(. Is there any way I can make this work? I'm at my wits end now :(

code.rhyme
  • 67
  • 4
  • 12
  • 1
    Just an FYI, XSLX files are ZIP files already. If you are trying to make them smaller by zipping them again, don't be surprised if that doesn't work. – Tomalak Nov 14 '16 at 17:48
  • Could you create a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) ? ".xls files does not open" could be a data corruption somewhere but we need the code to help you. – David Duponchel Nov 14 '16 at 18:33
  • hi @David I've added a modified code copy, of the approach I tried above. (I'm using alasql library for xlsx generation). – code.rhyme Nov 15 '16 at 09:27

2 Answers2

3

Not an answer (see below) but an explanation of what's going on:

To add a file, JSZip needs its binary content (as Blob, Uint8Array, etc). The line zip.file("test.xls", [newExcelData]); can't work for example: [newExcelData] is not a binary content but an array of js object.

What you need to figure out is how to get the content of the xlsx file. SELECT * INTO XLSX('Summary.xlsx') will trigger a download and return 1, it's not what you want. I searched on my side but can't find a way to do it with alasql.

Once/if you find the solution, the JSZip part looks correct.

Edit, following your switch to js-xlsx:

You use JSZip v2 (needed by js-xlsx) which doesn't support Blob inputs. However, wbout is a binary string which is supported:

zip.file("trial.xls", wbout, {binary: true});

Then, replace zip.generateAsync (added in JSZip v3):

var downloadFile = zip.generate({type: "blob" });
saveAs(downloadFile, 'test.zip');
Neo
  • 2,305
  • 4
  • 36
  • 70
David Duponchel
  • 3,959
  • 3
  • 28
  • 36
  • hi, is there any other js library that i can make use of, instead of alasql to generate excel file? That will make integrating with jsZip easy ? – code.rhyme Nov 16 '16 at 04:46
  • Hi @David, I've tried to make use of js-xlsx library - github.com/SheetJS/js-xlsx - for xls generation & compression. But, I'm getting console errors. Is this the approach I ought to follow?? Any way to make the above code work ? (P.S : I've even tried converting the data to a blob object, but getting above error on console.) – code.rhyme Nov 16 '16 at 06:20
1

Here is the solution I found using JSZip, XLSX and File Saver libraries.

Import:

import * as XLSX from "xlsx";
import JSZip from 'jszip';
import { saveAs } from 'file-saver';

Here is an example of compressing a .xlsx inside a zip:

let zip = new JSZip();
const jsonData = [
  {
     "Product": "Red Velvet Cupcake",
     "Price": "6",
     "GluttenFree": "Yes",
   },
   {
      "Product": "Cheesecake",
      "Price": "15",
      "GluttenFree": "No",
    }
];
const workBook: XLSX.WorkBook = XLSX.utils.book_new(); 
const workSheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(jsonData); 
XLSX.utils.book_append_sheet(workBook, workSheet, 'Bakery'); 
const workBookBuffer = XLSX.write(workBook, { bookType: 'xlsx', type: 'array' });

const fileData = new Blob([workBookBuffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'});        
zip.file('Products.xlsx', fileData);
zip.generateAsync({type:"blob"}).then(function (blob) {
saveAs(blob, "WorkBooks.zip");
});

This code generates a zip file named 'WorkBooks.zip' that contains the file 'Products.xlsx'. This is how the excel looks like:

enter image description here

Some file-saver examples: https://www.tabnine.com/code/javascript/modules/file-saver.

Here is the JSZip method used: https://stuk.github.io/jszip/documentation/api_jszip/file_data.html