API Improvements

- `aoa_to_sheet` function (fixes #314 h/t @fonzy2013 @rvdwijngaard)
- `writeFileAsync` function (fixes #396 h/t @barbalex)
- `sheet_to_json` tests + docs + blankrows (fixes #602 h/t @EEaglehouse)
- write number format scan now includes every index >= 50
- propagate SSF IE8 fixes (fixes #171 h/t @sheetjsdev)
- update shim for extendscript (see #603 h/t @firas3d)
- more flow type definitions
This commit is contained in:
SheetJS 2017-03-24 21:36:40 -04:00
parent 60e8905bcb
commit 70c48a74b9
22 changed files with 464 additions and 137 deletions

View File

@ -49,6 +49,7 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6.
* [Supported Output Formats](#supported-output-formats)
* [Output Type](#output-type)
- [Utility Functions](#utility-functions)
* [Array of Arrays Input](#array-of-arrays-input)
* [Formulae Output](#formulae-output)
* [CSV and general DSV Output](#csv-and-general-dsv-output)
* [JSON](#json)
@ -98,6 +99,7 @@ CDNjs automatically pulls the latest version and makes all versions available at
The `demos` directory includes sample projects for:
- [`angular`](demos/angular/)
- [`browserify`](demos/browserify/)
- [`requirejs`](demos/requirejs/)
- [`systemjs`](demos/systemjs/)
@ -377,12 +379,19 @@ Parse options are described in the [Parsing Options](#parsing-options) section.
`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`
`XLSX.writeFileAsync(filename, wb, o, cb)` attempts to write `wb` to `filename`.
If `o` is omitted, the writer will use the third argument as the callback.
Write options are described in the [Writing Options](#writing-options) section.
### Utilities
Utilities are available in the `XLSX.utils` object:
**Importing:**
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
**Exporting:**
- `sheet_to_json` converts a worksheet object to an array of JSON objects.
@ -655,7 +664,7 @@ objects which have the following properties:
```typescript
type ColInfo = {
MDW?:number; // Excel's "Max Digit Width" unit, always integral
width:number; // width in Excel's "Max Digit Width", width*256 is integral
width:number; // width in Excel's "Max Digit Width", width*256 is integral
wpx?:number; // width in screen pixels
wch?:number; // intermediate character calculation
};
@ -666,7 +675,8 @@ follow the priority order:
1) use `width` field if available
2) use `wpx` pixel width if available
2) use `wch` character count if available
3) use `wch` character count if available
## Parsing Options
The exported `read` and `readFile` functions accept an options argument:
@ -674,7 +684,7 @@ The exported `read` and `readFile` functions accept an options argument:
| Option Name | Default | Description |
| :---------- | ------: | :--------------------------------------------------- |
| type | | Input data encoding (see Input Type below) |
| cellFormula | true | Save formulae to the .f field ** |
| cellFormula | true | Save formulae to the .f field |
| cellHTML | true | Parse rich text and save HTML to the .h field |
| cellNF | false | Save number format string to the .z field |
| cellStyles | false | Save style/theme info to the .s field |
@ -689,8 +699,6 @@ The exported `read` and `readFile` functions accept an options argument:
| password | "" | If defined and file is encrypted, use password ** |
| WTF | false | If true, throw errors on unexpected file features ** |
- `cellFormula` option only applies to formats that require extra processing to
parse formulae (XLS/XLSB).
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
- In some cases, sheets may be parsed even if `bookSheets` is false.
- `bookSheets` and `bookProps` combine to give both sets of information
@ -794,6 +802,8 @@ The `type` argument for `write` mirrors the `type` argument for `read`:
The `sheet_to_*` functions accept a worksheet and an optional options object.
The `*_to_sheet` functions accept a data object and an optional options object.
The examples are based on the following worksheet:
```
@ -804,6 +814,30 @@ XXX| A | B | C | D | E | F | G |
3 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
```
### Array of Arrays Input
`XLSX.utils.aoa_to_sheet` takes an array of arrays of JS values and returns a
worksheet resembling the input data. Numbers, Booleans and Strings are stored
as the corresponding styles. Dates are stored as date or numbers. Array holes
and explicit `undefined` values are skipped. `null` values may be stubbed. All
other values are stored as strings. The function takes an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
| dateNF | fmt 14 | Use specified date format in string output |
| cellDates | false | Store dates as type `d` (default is `n`) |
| sheetStubs | false | Create cell objects of type `z` for `null` values |
To generate the example sheet:
```js
var ws = XLSX.utils.aoa_to_sheet([
"SheetJS".split(""),
[1,2,3,4,5,6,7],
[2,3,4,5,6,7,8]
]);
```
### Formulae Output
`XLSX.utils.sheet_to_formulae` generates an array of commands that represent
@ -828,8 +862,10 @@ produces CSV output. The function takes an options argument:
| RS | `"\n"` | "Record Separator" delimiter between rows |
| dateNF | fmt 14 | Use specified date format in string output |
| strip | false | Remove trailing field separators in each record ** |
| blankrows | true | Include blank lines in the CSV output |
- `strip` will remove trailing commas from each line under default `FS/RS`
- blankrows must be set to `false` to skip blank lines.
For the example sheet:
@ -858,6 +894,7 @@ generate different types of JS objects. The function takes an options argument:
| header | | Control output format (see table below) |
| dateNF | fmt 14 | Use specified date format in string output |
| defval | | Use specified value in place of null or undefined |
| blankrows | ** | Include blank lines in the output ** |
- `raw` only affects cells which have a format code (`.z`) field or a formatted
text (`.w`) field.
@ -869,6 +906,10 @@ generate different types of JS objects. The function takes an options argument:
- `null` values are returned when `raw` is true but are skipped when false.
- If `defval` is not specified, null and undefined values are skipped normally.
If specified, all null and undefined points will be filled with `defval`
- When `header` is `1`, the default is to generate blank rows. `blankrows` must
be set to `false` to skip blank rows.
- When `header` is not `1`, the default is to skip blank rows. `blankrows` must
be truthy to generate blank rows
`range` is expected to be one of:
@ -887,6 +928,9 @@ generate different types of JS objects. The function takes an options argument:
| array of strings | Use specified strings as keys in row objects |
| (default) | Read and disambiguate first row as keys |
If header is not `1`, the row object will contain the non-enumerable property
`__rowNum__` that represents the row of the sheet corresponding to the entry.
For the example sheet:
```js

View File

@ -332,7 +332,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt[1]==' '?2:1),val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
@ -358,7 +358,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_flt(type, "##########", val);
@ -370,7 +370,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
@ -441,7 +441,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt[1]==' '?2:1),val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
@ -471,7 +471,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_int(type, "##########", val);
@ -483,7 +483,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
@ -735,7 +735,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
vv = out[i].v.substr(j+1);
for(; j>=0; --j) {
if(jj>=0 && (out[i].v[j] === "0" || out[i].v[j] === "#")) vv = ostr[jj--] + vv;
if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
}
out[i].v = vv;
out[i].t = 't';
@ -748,7 +748,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
vv = out[i].v.substr(0,j);
for(; j<out[i].v.length; ++j) {
if(jj<ostr.length) vv += ostr[jj++];
if(jj<ostr.length) vv += ostr.charAt(jj++);
}
out[i].v = vv;
out[i].t = 't';

View File

@ -34,6 +34,18 @@ function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
function numdate(v/*:number*/)/*:Date*/ {
var date = SSF.parse_date_code(v);
var val = new Date();
if(date == null) throw new Error("Bad Date Code: " + v);
val.setUTCDate(date.d);
val.setUTCMonth(date.m-1);
val.setUTCFullYear(date.y);
val.setUTCHours(date.H);
val.setUTCMinutes(date.M);
val.setUTCSeconds(date.S);
return val;
}
/* ISO 8601 Duration */
function parse_isodur(s) {

36
bits/27_csfutils.js Normal file
View File

@ -0,0 +1,36 @@
function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
var n = opts && opts.sheet ? opts.sheet : "Sheet1";
var sheets = {}; sheets[n] = sheet;
return { SheetNames: [n], Sheets: sheets };
}
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var ws/*:Worksheet*/ = ({}/*:any*/);
var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/);
for(var R = 0; R != data.length; ++R) {
for(var C = 0; C != data[R].length; ++C) {
if(typeof data[R][C] === 'undefined') continue;
var cell/*:Cell*/ = ({v: data[R][C] }/*:any*/);
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_ref = encode_cell(({c:C,r:R}/*:any*/));
if(cell.v === null) { if(!o.cellStubs) continue; cell.t = 'z'; }
else if(typeof cell.v === 'number') cell.t = 'n';
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
cell.z = o.dateNF || SSF._table[14];
if(o.cellDates) cell.t = 'd';
else { cell.t = 'n'; cell.v = datenum(cell.v); }
cell.w = SSF.format(cell.z, cell.v);
}
else cell.t = 's';
ws[cell_ref] = cell;
}
}
if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
return ws;
}

View File

@ -222,7 +222,7 @@ function parse_numFmts(t, styles, opts) {
function write_numFmts(NF/*:{[n:number]:string}*/, opts) {
var o = ["<numFmts>"];
[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) {
[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
});
if(o.length === 1) return "";

View File

@ -806,18 +806,18 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
/* 2.5.198.31 TODO */
case 'PtgAreaN':
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls(r, opts));
stack.push(encode_range_xls((r/*:any*/), opts));
break;
/* 2.5.198.27 TODO: fixed points */
case 'PtgArea':
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls(r, opts));
stack.push(encode_range_xls((r/*:any*/), opts));
break;
/* 2.5.198.28 */
case 'PtgArea3d': // TODO: lots of stuff
type = f[1][0]; ixti = /*::Number(*/f[1][1]/*::)*/; r = f[1][2];
sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**");
stack.push(sname + "!" + encode_range(r));
stack.push(sname + "!" + encode_range((r/*:any*/)));
break;
/* 2.5.198.41 */
case 'PtgAttrSum':

View File

@ -167,6 +167,7 @@ function xlml_normalize(d)/*:string*/ {
var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts)/*:Workbook*/ {
make_ssf(SSF);
var str = debom(xlml_normalize(d));
if(opts && opts.type == 'binary' && typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);
@ -277,7 +278,10 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
break;
case 'NumberFormat':
stag.nf = xlml_parsexmltag(Rn[0]).Format || "General";
stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
break;
case 'Column':

View File

@ -85,7 +85,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
var out = {};
var Directory = {};
var found_sheet = false;
var range = {};
var range/*:Range*/ = ({}/*:any*/);
var last_formula = null;
var sst = [];
var cur_sheet = "";

View File

@ -59,9 +59,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
}
}
function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOpts*/) {
var o = opts||{}; o.type = 'file';
o.file = filename;
function resolve_book_type(o/*?WriteFileOpts*/) {
if(!o.bookType) switch(o.file.slice(-5).toLowerCase()) {
case '.xlsx': o.bookType = 'xlsx'; break;
case '.xlsm': o.bookType = 'xlsm'; break;
@ -74,6 +72,20 @@ function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOp
case '.ods': o.bookType = 'ods'; break;
case '.csv': o.bookType = 'csv'; break;
}}
}
function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOpts*/) {
var o = opts||{}; o.type = 'file';
o.file = filename;
resolve_book_type(o);
return writeSync(wb, o);
}
function writeFileAsync(filename/*:string*/, wb/*:Workbook*/, opts/*:?WriteFileOpts*/, cb/*:?(e?:ErrnoError)=>void*/) {
var o = opts||{}; o.type = 'file';
o.file = filename;
resolve_book_type(o);
o.type = 'buffer';
var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts/*:any*/);
return _fs.writeFile(filename, writeSync(wb, o), _cb);
}

View File

@ -14,7 +14,8 @@ function encode_cell(cell/*:CellAddress*/)/*:string*/ { return encode_col(cell.c
function fix_cell(cstr/*:string*/)/*:string*/ { return fix_col(fix_row(cstr)); }
function unfix_cell(cstr/*:string*/)/*:string*/ { return unfix_col(unfix_row(cstr)); }
function decode_range(range/*:string*/)/*:Range*/ { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
function encode_range(cs/*:any*/,ce/*:?any*/)/*:string*/ {
/*# if only one arg, it is assumed to be a Range. If 2 args, both are cell addresses */
function encode_range(cs/*:CellAddrSpec|Range*/,ce/*:?CellAddrSpec*/)/*:string*/ {
if(typeof ce === 'undefined' || typeof ce === 'number') {
/*:: if(!(cs instanceof Range)) throw "unreachable"; */
return encode_range(cs.s, cs.e);
@ -69,8 +70,8 @@ function format_cell(cell/*:Cell*/, v/*:any*/, o/*:any*/) {
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
if(v == undefined) return safe_format_cell(cell, cell.v);
return safe_format_cell(cell, v);
if(v == undefined) return safe_format_cell(cell, cell.v, o);
return safe_format_cell(cell, v, o);
}
function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
@ -102,7 +103,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
case 3: hdr[C] = o.header[C - r.s.c]; break;
default:
if(val == null) continue;
vv = v = format_cell(val);
vv = v = format_cell(val, null, o);
var counter = 0;
for(var CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
hdr[C] = vv;
@ -138,19 +139,17 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw ? v : format_cell(val,v);
row[hdr[C]] = raw ? v : format_cell(val,v,o);
}
isempty = false;
}
}
if(isempty === false || header === 1) out[outi++] = row;
if((isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row;
}
out.length = outi;
return out;
}
function sheet_to_row_object_array(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { return sheet_to_json(sheet, opts != null ? opts : {}); }
function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
var out = "", txt = "", qreg = /"/g;
var o = opts == null ? {} : opts;
@ -158,27 +157,31 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
var r = safe_decode_range(sheet["!ref"]);
var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
var endregex = new RegExp(FS+"+$");
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
var row = "", rr = "", cols = [];
var i = 0, cc = 0, val;
var R = 0, C = 0;
for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
for(R = r.s.r; R <= r.e.r; ++R) {
var isempty = true;
row = "";
rr = encode_row(R);
for(C = r.s.c; C <= r.e.c; ++C) {
val = sheet[cols[C] + rr];
if(val == null) txt = "";
else if(val.v != null) {
txt = ''+format_cell(val);
isempty = false;
txt = ''+format_cell(val, null, o);
for(i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {
txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
} else if(val.f != null && !val.F) {
isempty = false;
txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
} else txt = "";
/* NOTE: Excel CSV does not support array formulae */
row += (C === r.s.c ? "" : FS) + txt;
}
if(o.blankrows === false && isempty) continue;
if(o.strip) row = row.replace(endregex,"");
out += row + RS;
}
@ -236,8 +239,9 @@ var utils = {
make_csv: sheet_to_csv,
make_json: sheet_to_json,
make_formulae: sheet_to_formulae,
aoa_to_sheet: aoa_to_sheet,
sheet_to_csv: sheet_to_csv,
sheet_to_json: sheet_to_json,
sheet_to_formulae: sheet_to_formulae,
sheet_to_row_object_array: sheet_to_row_object_array
sheet_to_row_object_array: sheet_to_json
};

View File

@ -9,6 +9,7 @@ XLSX.readFileSync = readFileSync;
XLSX.write = writeSync;
XLSX.writeFile = writeFileSync;
XLSX.writeFileSync = writeFileSync;
XLSX.writeFileAsync = writeFileAsync;
XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;

View File

@ -25,6 +25,7 @@ CDNjs automatically pulls the latest version and makes all versions available at
The `demos` directory includes sample projects for:
- [`angular`](demos/angular/)
- [`browserify`](demos/browserify/)
- [`requirejs`](demos/requirejs/)
- [`systemjs`](demos/systemjs/)

View File

@ -20,12 +20,19 @@ Parse options are described in the [Parsing Options](#parsing-options) section.
`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`
`XLSX.writeFileAsync(filename, wb, o, cb)` attempts to write `wb` to `filename`.
If `o` is omitted, the writer will use the third argument as the callback.
Write options are described in the [Writing Options](#writing-options) section.
### Utilities
Utilities are available in the `XLSX.utils` object:
**Importing:**
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
**Exporting:**
- `sheet_to_json` converts a worksheet object to an array of JSON objects.

View File

@ -17,7 +17,7 @@ objects which have the following properties:
```typescript
type ColInfo = {
MDW?:number; // Excel's "Max Digit Width" unit, always integral
width:number; // width in Excel's "Max Digit Width", width*256 is integral
width:number; // width in Excel's "Max Digit Width", width*256 is integral
wpx?:number; // width in screen pixels
wch?:number; // intermediate character calculation
};
@ -28,4 +28,5 @@ follow the priority order:
1) use `width` field if available
2) use `wpx` pixel width if available
2) use `wch` character count if available
3) use `wch` character count if available

View File

@ -5,7 +5,7 @@ The exported `read` and `readFile` functions accept an options argument:
| Option Name | Default | Description |
| :---------- | ------: | :--------------------------------------------------- |
| type | | Input data encoding (see Input Type below) |
| cellFormula | true | Save formulae to the .f field ** |
| cellFormula | true | Save formulae to the .f field |
| cellHTML | true | Parse rich text and save HTML to the .h field |
| cellNF | false | Save number format string to the .z field |
| cellStyles | false | Save style/theme info to the .s field |
@ -20,8 +20,6 @@ The exported `read` and `readFile` functions accept an options argument:
| password | "" | If defined and file is encrypted, use password ** |
| WTF | false | If true, throw errors on unexpected file features ** |
- `cellFormula` option only applies to formats that require extra processing to
parse formulae (XLS/XLSB).
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
- In some cases, sheets may be parsed even if `bookSheets` is false.
- `bookSheets` and `bookProps` combine to give both sets of information

View File

@ -2,6 +2,8 @@
The `sheet_to_*` functions accept a worksheet and an optional options object.
The `*_to_sheet` functions accept a data object and an optional options object.
The examples are based on the following worksheet:
```
@ -12,6 +14,30 @@ XXX| A | B | C | D | E | F | G |
3 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
```
### Array of Arrays Input
`XLSX.utils.aoa_to_sheet` takes an array of arrays of JS values and returns a
worksheet resembling the input data. Numbers, Booleans and Strings are stored
as the corresponding styles. Dates are stored as date or numbers. Array holes
and explicit `undefined` values are skipped. `null` values may be stubbed. All
other values are stored as strings. The function takes an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
| dateNF | fmt 14 | Use specified date format in string output |
| cellDates | false | Store dates as type `d` (default is `n`) |
| sheetStubs | false | Create cell objects of type `z` for `null` values |
To generate the example sheet:
```js
var ws = XLSX.utils.aoa_to_sheet([
"SheetJS".split(""),
[1,2,3,4,5,6,7],
[2,3,4,5,6,7,8]
]);
```
### Formulae Output
`XLSX.utils.sheet_to_formulae` generates an array of commands that represent
@ -36,8 +62,10 @@ produces CSV output. The function takes an options argument:
| RS | `"\n"` | "Record Separator" delimiter between rows |
| dateNF | fmt 14 | Use specified date format in string output |
| strip | false | Remove trailing field separators in each record ** |
| blankrows | true | Include blank lines in the CSV output |
- `strip` will remove trailing commas from each line under default `FS/RS`
- blankrows must be set to `false` to skip blank lines.
For the example sheet:
@ -66,6 +94,7 @@ generate different types of JS objects. The function takes an options argument:
| header | | Control output format (see table below) |
| dateNF | fmt 14 | Use specified date format in string output |
| defval | | Use specified value in place of null or undefined |
| blankrows | ** | Include blank lines in the output ** |
- `raw` only affects cells which have a format code (`.z`) field or a formatted
text (`.w`) field.
@ -77,6 +106,10 @@ generate different types of JS objects. The function takes an options argument:
- `null` values are returned when `raw` is true but are skipped when false.
- If `defval` is not specified, null and undefined values are skipped normally.
If specified, all null and undefined points will be filled with `defval`
- When `header` is `1`, the default is to generate blank rows. `blankrows` must
be set to `false` to skip blank rows.
- When `header` is not `1`, the default is to skip blank rows. `blankrows` must
be truthy to generate blank rows
`range` is expected to be one of:
@ -95,6 +128,9 @@ generate different types of JS objects. The function takes an options argument:
| array of strings | Use specified strings as keys in row objects |
| (default) | Read and disambiguate first row as keys |
If header is not `1`, the row object will contain the non-enumerable property
`__rowNum__` that represents the row of the sheet corresponding to the entry.
For the example sheet:
```js

View File

@ -9,7 +9,7 @@ Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/js
JSZip uses the library pako released under the MIT license :
https://github.com/nodeca/pako/blob/master/LICENSE
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd){JSZip=e();define([],e);}else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd){JSZip=e();define([],e);}else{if(typeof self == 'undefined' && typeof app != 'undefined') self = app;var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
'use strict';
// private property
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
@ -1005,10 +1005,6 @@ var generateZipParts = function(name, file, compressedObject, offset) {
date = o.date;
}
// date
// @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
// @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
// @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
dosTime = date.getHours();
dosTime = dosTime << 6;

View File

@ -25,6 +25,7 @@ interface CellAddress {
r:number;
c:number;
};
type CellAddrSpec = CellAddress | string;
type Cell = any;
@ -66,4 +67,6 @@ type ColInfo = {
wpx?:number; // width in screen pixels
wch?:number; // intermediate character calculation
};
type AOA = Array<Array<any> >;
*/

View File

@ -242,7 +242,7 @@ if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
;(function () {
var object = typeof exports != 'undefined' ? exports : self; // #8: web workers
var object = typeof exports != 'undefined' ? exports : typeof self != 'undefined' ? self : (1,eval)("this");
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
function InvalidCharacterError(message) {
@ -279,7 +279,7 @@ if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
// [https://gist.github.com/1020396] by [https://github.com/atk]
object.atob || (
object.atob = function (input) {
var str = String(input).replace(/=+$/, '');
var str = String(input).replace(new RegExp("=+$"), '');
if (str.length % 4 == 1) {
throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
}
@ -299,7 +299,7 @@ if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
}
return output;
});
if(typeof app != 'undefined') { app.btoa = object.btoa; app.atob = object.atob; }
}());

107
test.js
View File

@ -1041,33 +1041,6 @@ function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (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 === undefined) continue;
var cell_ref = X.utils.encode_cell({c:C,r:R});
if(cell.v === null) cell.t = 'z';
else if(typeof cell.v === 'number') cell.t = 'n';
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
cell.z = X.SSF._table[14];
if(opts && opts.cellDates) cell.t = 'd';
else { cell.t = 'n'; cell.v = datenum(cell.v); }
}
else cell.t = 's';
ws[cell_ref] = cell;
}
}
if(range.s.c < 10000000) ws['!ref'] = X.utils.encode_range(range);
return ws;
}
describe('json output', function() {
function seeker(json, keys, val) {
@ -1085,7 +1058,7 @@ describe('json output', function() {
["foo", "bar", new Date("2014-02-19T14:30Z"), "0.3"],
["baz", undefined, "qux"]
];
ws = sheet_from_array_of_arrays(data);
ws = X.utils.aoa_to_sheet(data);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
@ -1142,8 +1115,6 @@ describe('json output', function() {
});
it('should use defval if requested', function() {
var json = X.utils.sheet_to_json(ws, {defval: 'jimjin'});
console.log(json);
console.log(ws);
assert.equal(json.length, data.length - 1);
assert.equal(json[0][1], "TRUE");
assert.equal(json[1][2], "bar");
@ -1153,13 +1124,11 @@ describe('json output', function() {
assert.doesNotThrow(function() { seeker(json, [1,2,3], "sheetjs"); });
assert.throws(function() { seeker(json, [1,2,3], "baz"); });
var json = X.utils.sheet_to_json(ws, {raw:true});
console.log(json);
var json = X.utils.sheet_to_json(ws, {raw:true, defval: 'jimjin'});
console.log(json);
});
it('should disambiguate headers', function() {
var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[2,3,4,5,6,7,8]];
var _ws = sheet_from_array_of_arrays(_data);
var _ws = X.utils.aoa_to_sheet(_data);
var json = X.utils.sheet_to_json(_ws);
for(var i = 0; i < json.length; ++i) {
assert.equal(json[i].S, 1 + i);
@ -1172,7 +1141,7 @@ describe('json output', function() {
}
});
it('should handle raw data if requested', function() {
var _ws = sheet_from_array_of_arrays(data, {cellDates:true});
var _ws = X.utils.aoa_to_sheet(data, {cellDates:true});
var json = X.utils.sheet_to_json(_ws, {header:1, raw:true});
assert.equal(json.length, data.length);
assert.equal(json[1][0], true);
@ -1181,6 +1150,72 @@ describe('json output', function() {
assert.equal(json[2][2].getTime(), new Date("2014-02-19T14:30Z").getTime());
assert.equal(json[3][2], "qux");
});
it('should include __rowNum__', function() {
var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[],[2,3,4,5,6,7,8]];
var _ws = X.utils.aoa_to_sheet(_data);
var json = X.utils.sheet_to_json(_ws);
assert.equal(json[0].__rowNum__, 1);
assert.equal(json[1].__rowNum__, 3);
});
it('should handle blankrows', function() {
var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[],[2,3,4,5,6,7,8]];
var _ws = X.utils.aoa_to_sheet(_data);
var json1 = X.utils.sheet_to_json(_ws);
var json2 = X.utils.sheet_to_json(_ws, {header:1});
var json3 = X.utils.sheet_to_json(_ws, {blankrows:true});
var json4 = X.utils.sheet_to_json(_ws, {blankrows:true, header:1});
var json5 = X.utils.sheet_to_json(_ws, {blankrows:false});
var json6 = X.utils.sheet_to_json(_ws, {blankrows:false, header:1});
assert.equal(json1.length, 2); // = 2 non-empty records
assert.equal(json2.length, 4); // = 4 sheet rows
assert.equal(json3.length, 3); // = 2 records + 1 blank row
assert.equal(json4.length, 4); // = 4 sheet rows
assert.equal(json5.length, 2); // = 2 records
assert.equal(json6.length, 3); // = 4 sheet rows - 1 blank row
});
});
describe('csv output', function() {
var data, ws;
var bef = (function() {
data = [
[1,2,3,null],
[true, false, null, "sheetjs"],
["foo", "bar", new Date("2014-02-19T14:30Z"), "0.3"],
[null, null, null],
["baz", undefined, "qux"]
];
ws = X.utils.aoa_to_sheet(data);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it('should generate csv', function() {
var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n";
assert.equal(baseline, X.utils.sheet_to_csv(ws));
});
it('should handle FS', function() {
assert.equal(X.utils.sheet_to_csv(ws, {FS:"|"}).replace(/[|]/g,","), X.utils.sheet_to_csv(ws));
assert.equal(X.utils.sheet_to_csv(ws, {FS:";"}).replace(/[;]/g,","), X.utils.sheet_to_csv(ws));
});
it('should handle RS', function() {
assert.equal(X.utils.sheet_to_csv(ws, {RS:"|"}).replace(/[|]/g,"\n"), X.utils.sheet_to_csv(ws));
assert.equal(X.utils.sheet_to_csv(ws, {RS:";"}).replace(/[;]/g,"\n"), X.utils.sheet_to_csv(ws));
});
it('should handle dateNF', function() {
var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,20140219,0.3\n,,,\nbaz,,qux,\n";
var _ws = X.utils.aoa_to_sheet(data, {cellDates:true});
delete _ws.C3.w;
delete _ws.C3.z;
assert.equal(baseline, X.utils.sheet_to_csv(_ws, {dateNF:"YYYYMMDD"}));
});
it('should handle strip', function() {
var baseline = "1,2,3\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n\nbaz,,qux\n";
assert.equal(baseline, X.utils.sheet_to_csv(ws, {strip:true}));
});
it('should handle blankrows', function() {
var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\nbaz,,qux,\n";
assert.equal(baseline, X.utils.sheet_to_csv(ws, {blankrows:false}));
});
});
describe('js -> file -> js', function() {
@ -1192,7 +1227,7 @@ describe('js -> file -> js', function() {
["foo","bar",new Date("2014-02-19T14:30Z"), "0.3"],
["baz", 6.9, "qux"]
];
ws = sheet_from_array_of_arrays(data);
ws = X.utils.aoa_to_sheet(data);
wb = { SheetNames: ['Sheet1'], Sheets: {Sheet1: ws} };
});
if(typeof before != 'undefined') before(bef);
@ -1234,7 +1269,7 @@ describe('corner cases', function() {
["foo","bar",new Date("2014-02-19T14:30Z"), "0.3"],
["baz", null, "q\"ux"]
];
var ws = sheet_from_array_of_arrays(data);
var ws = X.utils.aoa_to_sheet(data);
ws.A1.f = ""; ws.A1.w = "";
delete ws.C3.w; delete ws.C3.z; ws.C3.XF = {ifmt:14};
ws.A4.t = "e";

View File

@ -444,7 +444,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt[1]==' '?2:1),val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
@ -470,7 +470,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_flt(type, "##########", val);
@ -482,7 +482,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
@ -553,7 +553,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt[1]==' '?2:1),val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
@ -583,7 +583,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_int(type, "##########", val);
@ -595,7 +595,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
@ -847,7 +847,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
vv = out[i].v.substr(j+1);
for(; j>=0; --j) {
if(jj>=0 && (out[i].v[j] === "0" || out[i].v[j] === "#")) vv = ostr[jj--] + vv;
if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
}
out[i].v = vv;
out[i].t = 't';
@ -860,7 +860,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
vv = out[i].v.substr(0,j);
for(; j<out[i].v.length; ++j) {
if(jj<ostr.length) vv += ostr[jj++];
if(jj<ostr.length) vv += ostr.charAt(jj++);
}
out[i].v = vv;
out[i].t = 't';
@ -1401,6 +1401,18 @@ function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
function numdate(v/*:number*/)/*:Date*/ {
var date = SSF.parse_date_code(v);
var val = new Date();
if(date == null) throw new Error("Bad Date Code: " + v);
val.setUTCDate(date.d);
val.setUTCMonth(date.m-1);
val.setUTCFullYear(date.y);
val.setUTCHours(date.H);
val.setUTCMinutes(date.M);
val.setUTCSeconds(date.S);
return val;
}
/* ISO 8601 Duration */
function parse_isodur(s) {
@ -2049,6 +2061,42 @@ var make_offcrypto = function(O, _crypto) {
/*:: declare var crypto:any; */
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
var n = opts && opts.sheet ? opts.sheet : "Sheet1";
var sheets = {}; sheets[n] = sheet;
return { SheetNames: [n], Sheets: sheets };
}
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var ws/*:Worksheet*/ = ({}/*:any*/);
var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/);
for(var R = 0; R != data.length; ++R) {
for(var C = 0; C != data[R].length; ++C) {
if(typeof data[R][C] === 'undefined') continue;
var cell/*:Cell*/ = ({v: data[R][C] }/*:any*/);
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_ref = encode_cell(({c:C,r:R}/*:any*/));
if(cell.v === null) { if(!o.cellStubs) continue; cell.t = 'z'; }
else if(typeof cell.v === 'number') cell.t = 'n';
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
cell.z = o.dateNF || SSF._table[14];
if(o.cellDates) cell.t = 'd';
else { cell.t = 'n'; cell.v = datenum(cell.v); }
cell.w = SSF.format(cell.z, cell.v);
}
else cell.t = 's';
ws[cell_ref] = cell;
}
}
if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
return ws;
}
/* [MS-XLSB] 2.5.143 */
function parse_StrRun(data, length/*:?number*/) {
@ -5389,7 +5437,7 @@ function parse_numFmts(t, styles, opts) {
function write_numFmts(NF/*:{[n:number]:string}*/, opts) {
var o = ["<numFmts>"];
[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) {
[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
});
if(o.length === 1) return "";
@ -7029,18 +7077,18 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
/* 2.5.198.31 TODO */
case 'PtgAreaN':
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls(r, opts));
stack.push(encode_range_xls((r/*:any*/), opts));
break;
/* 2.5.198.27 TODO: fixed points */
case 'PtgArea':
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls(r, opts));
stack.push(encode_range_xls((r/*:any*/), opts));
break;
/* 2.5.198.28 */
case 'PtgArea3d': // TODO: lots of stuff
type = f[1][0]; ixti = /*::Number(*/f[1][1]/*::)*/; r = f[1][2];
sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**");
stack.push(sname + "!" + encode_range(r));
stack.push(sname + "!" + encode_range((r/*:any*/)));
break;
/* 2.5.198.41 */
case 'PtgAttrSum':
@ -10225,6 +10273,7 @@ function xlml_normalize(d)/*:string*/ {
var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts)/*:Workbook*/ {
make_ssf(SSF);
var str = debom(xlml_normalize(d));
if(opts && opts.type == 'binary' && typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);
@ -10335,7 +10384,10 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
break;
case 'NumberFormat':
stag.nf = xlml_parsexmltag(Rn[0]).Format || "General";
stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
break;
case 'Column':
@ -11012,7 +11064,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
var out = {};
var Directory = {};
var found_sheet = false;
var range = {};
var range/*:Range*/ = ({}/*:any*/);
var last_formula = null;
var sst = [];
var cur_sheet = "";
@ -13977,9 +14029,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
}
}
function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOpts*/) {
var o = opts||{}; o.type = 'file';
o.file = filename;
function resolve_book_type(o/*?WriteFileOpts*/) {
if(!o.bookType) switch(o.file.slice(-5).toLowerCase()) {
case '.xlsx': o.bookType = 'xlsx'; break;
case '.xlsm': o.bookType = 'xlsm'; break;
@ -13992,9 +14042,23 @@ function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOp
case '.ods': o.bookType = 'ods'; break;
case '.csv': o.bookType = 'csv'; break;
}}
}
function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOpts*/) {
var o = opts||{}; o.type = 'file';
o.file = filename;
resolve_book_type(o);
return writeSync(wb, o);
}
function writeFileAsync(filename/*:string*/, wb/*:Workbook*/, opts/*:?WriteFileOpts*/, cb/*:?(e?:ErrnoError)=>void*/) {
var o = opts||{}; o.type = 'file';
o.file = filename;
resolve_book_type(o);
o.type = 'buffer';
var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts/*:any*/);
return _fs.writeFile(filename, writeSync(wb, o), _cb);
}
function decode_row(rowstr/*:string*/)/*:number*/ { return parseInt(unfix_row(rowstr),10) - 1; }
function encode_row(row/*:number*/)/*:string*/ { return "" + (row + 1); }
function fix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
@ -14011,7 +14075,8 @@ function encode_cell(cell/*:CellAddress*/)/*:string*/ { return encode_col(cell.c
function fix_cell(cstr/*:string*/)/*:string*/ { return fix_col(fix_row(cstr)); }
function unfix_cell(cstr/*:string*/)/*:string*/ { return unfix_col(unfix_row(cstr)); }
function decode_range(range/*:string*/)/*:Range*/ { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
function encode_range(cs/*:any*/,ce/*:?any*/)/*:string*/ {
/*# if only one arg, it is assumed to be a Range. If 2 args, both are cell addresses */
function encode_range(cs/*:CellAddrSpec|Range*/,ce/*:?CellAddrSpec*/)/*:string*/ {
if(typeof ce === 'undefined' || typeof ce === 'number') {
/*:: if(!(cs instanceof Range)) throw "unreachable"; */
return encode_range(cs.s, cs.e);
@ -14066,8 +14131,8 @@ function format_cell(cell/*:Cell*/, v/*:any*/, o/*:any*/) {
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
if(v == undefined) return safe_format_cell(cell, cell.v);
return safe_format_cell(cell, v);
if(v == undefined) return safe_format_cell(cell, cell.v, o);
return safe_format_cell(cell, v, o);
}
function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
@ -14099,7 +14164,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
case 3: hdr[C] = o.header[C - r.s.c]; break;
default:
if(val == null) continue;
vv = v = format_cell(val);
vv = v = format_cell(val, null, o);
var counter = 0;
for(var CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
hdr[C] = vv;
@ -14135,19 +14200,17 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw ? v : format_cell(val,v);
row[hdr[C]] = raw ? v : format_cell(val,v,o);
}
isempty = false;
}
}
if(isempty === false || header === 1) out[outi++] = row;
if((isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row;
}
out.length = outi;
return out;
}
function sheet_to_row_object_array(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { return sheet_to_json(sheet, opts != null ? opts : {}); }
function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
var out = "", txt = "", qreg = /"/g;
var o = opts == null ? {} : opts;
@ -14155,27 +14218,31 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
var r = safe_decode_range(sheet["!ref"]);
var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
var endregex = new RegExp(FS+"+$");
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
var row = "", rr = "", cols = [];
var i = 0, cc = 0, val;
var R = 0, C = 0;
for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
for(R = r.s.r; R <= r.e.r; ++R) {
var isempty = true;
row = "";
rr = encode_row(R);
for(C = r.s.c; C <= r.e.c; ++C) {
val = sheet[cols[C] + rr];
if(val == null) txt = "";
else if(val.v != null) {
txt = ''+format_cell(val);
isempty = false;
txt = ''+format_cell(val, null, o);
for(i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {
txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
} else if(val.f != null && !val.F) {
isempty = false;
txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
} else txt = "";
/* NOTE: Excel CSV does not support array formulae */
row += (C === r.s.c ? "" : FS) + txt;
}
if(o.blankrows === false && isempty) continue;
if(o.strip) row = row.replace(endregex,"");
out += row + RS;
}
@ -14233,10 +14300,11 @@ var utils = {
make_csv: sheet_to_csv,
make_json: sheet_to_json,
make_formulae: sheet_to_formulae,
aoa_to_sheet: aoa_to_sheet,
sheet_to_csv: sheet_to_csv,
sheet_to_json: sheet_to_json,
sheet_to_formulae: sheet_to_formulae,
sheet_to_row_object_array: sheet_to_row_object_array
sheet_to_row_object_array: sheet_to_json
};
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
@ -14249,6 +14317,7 @@ XLSX.readFileSync = readFileSync;
XLSX.write = writeSync;
XLSX.writeFile = writeFileSync;
XLSX.writeFileSync = writeFileSync;
XLSX.writeFileAsync = writeFileAsync;
XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;

122
xlsx.js
View File

@ -425,7 +425,7 @@ function write_num_flt(type, fmt, val) {
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt[1]==' '?2:1),val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
@ -451,7 +451,7 @@ function write_num_flt(type, fmt, val) {
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_flt(type, "##########", val);
@ -463,7 +463,7 @@ function write_num_flt(type, fmt, val) {
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
@ -534,7 +534,7 @@ function write_num_int(type, fmt, val) {
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt[1]==' '?2:1),val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
@ -562,7 +562,7 @@ return "." + $1 + fill("0", r[1].length-$1.length); });
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_int(type, "##########", val);
@ -574,7 +574,7 @@ return "." + $1 + fill("0", r[1].length-$1.length); });
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
@ -823,7 +823,7 @@ out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
vv = out[i].v.substr(j+1);
for(; j>=0; --j) {
if(jj>=0 && (out[i].v[j] === "0" || out[i].v[j] === "#")) vv = ostr[jj--] + vv;
if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
}
out[i].v = vv;
out[i].t = 't';
@ -836,7 +836,7 @@ out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
vv = out[i].v.substr(0,j);
for(; j<out[i].v.length; ++j) {
if(jj<ostr.length) vv += ostr[jj++];
if(jj<ostr.length) vv += ostr.charAt(jj++);
}
out[i].v = vv;
out[i].t = 't';
@ -1353,6 +1353,18 @@ function datenum(v, date1904) {
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
function numdate(v) {
var date = SSF.parse_date_code(v);
var val = new Date();
if(date == null) throw new Error("Bad Date Code: " + v);
val.setUTCDate(date.d);
val.setUTCMonth(date.m-1);
val.setUTCFullYear(date.y);
val.setUTCHours(date.H);
val.setUTCMinutes(date.M);
val.setUTCSeconds(date.S);
return val;
}
/* ISO 8601 Duration */
function parse_isodur(s) {
@ -1997,6 +2009,42 @@ var make_offcrypto = function(O, _crypto) {
};
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
function sheet_to_workbook(sheet, opts) {
var n = opts && opts.sheet ? opts.sheet : "Sheet1";
var sheets = {}; sheets[n] = sheet;
return { SheetNames: [n], Sheets: sheets };
}
function aoa_to_sheet(data, opts) {
var o = 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(typeof data[R][C] === 'undefined') continue;
var cell = ({v: data[R][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_ref = encode_cell(({c:C,r:R}));
if(cell.v === null) { if(!o.cellStubs) continue; cell.t = 'z'; }
else if(typeof cell.v === 'number') cell.t = 'n';
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
cell.z = o.dateNF || SSF._table[14];
if(o.cellDates) cell.t = 'd';
else { cell.t = 'n'; cell.v = datenum(cell.v); }
cell.w = SSF.format(cell.z, cell.v);
}
else cell.t = 's';
ws[cell_ref] = cell;
}
}
if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
return ws;
}
/* [MS-XLSB] 2.5.143 */
function parse_StrRun(data, length) {
@ -5335,7 +5383,7 @@ function parse_numFmts(t, styles, opts) {
function write_numFmts(NF, opts) {
var o = ["<numFmts>"];
[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) {
[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
});
if(o.length === 1) return "";
@ -6974,18 +7022,18 @@ function stringify_formula(formula/*Array<any>*/, range, cell, supbooks, opts) {
/* 2.5.198.31 TODO */
case 'PtgAreaN':
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls(r, opts));
stack.push(encode_range_xls((r), opts));
break;
/* 2.5.198.27 TODO: fixed points */
case 'PtgArea':
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls(r, opts));
stack.push(encode_range_xls((r), opts));
break;
/* 2.5.198.28 */
case 'PtgArea3d': // TODO: lots of stuff
type = f[1][0]; ixti = f[1][1]; r = f[1][2];
sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**");
stack.push(sname + "!" + encode_range(r));
stack.push(sname + "!" + encode_range((r)));
break;
/* 2.5.198.41 */
case 'PtgAttrSum':
@ -10168,6 +10216,7 @@ function xlml_normalize(d) {
var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts) {
make_ssf(SSF);
var str = debom(xlml_normalize(d));
if(opts && opts.type == 'binary' && typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);
@ -10277,7 +10326,10 @@ for(var cma = c; cma <= cc; ++cma) {
break;
case 'NumberFormat':
stag.nf = xlml_parsexmltag(Rn[0]).Format || "General";
stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
break;
case 'Column':
@ -10953,7 +11005,7 @@ function parse_workbook(blob, options) {
var out = {};
var Directory = {};
var found_sheet = false;
var range = {};
var range = ({});
var last_formula = null;
var sst = [];
var cur_sheet = "";
@ -13914,9 +13966,7 @@ function writeSync(wb, opts) {
}
}
function writeFileSync(wb, filename, opts) {
var o = opts||{}; o.type = 'file';
o.file = filename;
function resolve_book_type(o/*?WriteFileOpts*/) {
if(!o.bookType) switch(o.file.slice(-5).toLowerCase()) {
case '.xlsx': o.bookType = 'xlsx'; break;
case '.xlsm': o.bookType = 'xlsm'; break;
@ -13929,9 +13979,23 @@ function writeFileSync(wb, filename, opts) {
case '.ods': o.bookType = 'ods'; break;
case '.csv': o.bookType = 'csv'; break;
}}
}
function writeFileSync(wb, filename, opts) {
var o = opts||{}; o.type = 'file';
o.file = filename;
resolve_book_type(o);
return writeSync(wb, o);
}
function writeFileAsync(filename, wb, opts, cb) {
var o = opts||{}; o.type = 'file';
o.file = filename;
resolve_book_type(o);
o.type = 'buffer';
var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
return _fs.writeFile(filename, writeSync(wb, o), _cb);
}
function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
function encode_row(row) { return "" + (row + 1); }
function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
@ -13999,8 +14063,8 @@ function format_cell(cell, v, o) {
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
if(v == undefined) return safe_format_cell(cell, cell.v);
return safe_format_cell(cell, v);
if(v == undefined) return safe_format_cell(cell, cell.v, o);
return safe_format_cell(cell, v, o);
}
function sheet_to_json(sheet, opts){
@ -14032,7 +14096,7 @@ function sheet_to_json(sheet, opts){
case 3: hdr[C] = o.header[C - r.s.c]; break;
default:
if(val == null) continue;
vv = v = format_cell(val);
vv = v = format_cell(val, null, o);
var counter = 0;
for(var CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
hdr[C] = vv;
@ -14068,19 +14132,17 @@ function sheet_to_json(sheet, opts){
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw ? v : format_cell(val,v);
row[hdr[C]] = raw ? v : format_cell(val,v,o);
}
isempty = false;
}
}
if(isempty === false || header === 1) out[outi++] = row;
if((isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row;
}
out.length = outi;
return out;
}
function sheet_to_row_object_array(sheet, opts) { return sheet_to_json(sheet, opts != null ? opts : {}); }
function sheet_to_csv(sheet, opts) {
var out = "", txt = "", qreg = /"/g;
var o = opts == null ? {} : opts;
@ -14088,27 +14150,31 @@ function sheet_to_csv(sheet, opts) {
var r = safe_decode_range(sheet["!ref"]);
var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
var endregex = new RegExp(FS+"+$");
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
var row = "", rr = "", cols = [];
var i = 0, cc = 0, val;
var R = 0, C = 0;
for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
for(R = r.s.r; R <= r.e.r; ++R) {
var isempty = true;
row = "";
rr = encode_row(R);
for(C = r.s.c; C <= r.e.c; ++C) {
val = sheet[cols[C] + rr];
if(val == null) txt = "";
else if(val.v != null) {
txt = ''+format_cell(val);
isempty = false;
txt = ''+format_cell(val, null, o);
for(i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {
txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
} else if(val.f != null && !val.F) {
isempty = false;
txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
} else txt = "";
/* NOTE: Excel CSV does not support array formulae */
row += (C === r.s.c ? "" : FS) + txt;
}
if(o.blankrows === false && isempty) continue;
if(o.strip) row = row.replace(endregex,"");
out += row + RS;
}
@ -14166,10 +14232,11 @@ var utils = {
make_csv: sheet_to_csv,
make_json: sheet_to_json,
make_formulae: sheet_to_formulae,
aoa_to_sheet: aoa_to_sheet,
sheet_to_csv: sheet_to_csv,
sheet_to_json: sheet_to_json,
sheet_to_formulae: sheet_to_formulae,
sheet_to_row_object_array: sheet_to_row_object_array
sheet_to_row_object_array: sheet_to_json
};
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
@ -14182,6 +14249,7 @@ XLSX.readFileSync = readFileSync;
XLSX.write = writeSync;
XLSX.writeFile = writeFileSync;
XLSX.writeFileSync = writeFileSync;
XLSX.writeFileAsync = writeFileAsync;
XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;