From 9ae3a64af8bdd1c7cdbfb5b050b1e4302d0df85c Mon Sep 17 00:00:00 2001 From: Jim Date: Thu, 23 Mar 2017 13:54:27 +0800 Subject: [PATCH] `sheet_to_json` default value uses `defval` key in options object fixes #583 h/t @jimjin fixes #582 h/t @jimjin fixes #147 h/t @jtadmor --- CHANGELOG.md | 5 +++++ README.md | 4 ++++ bits/90_utils.js | 19 +++++++++++++++---- docbits/82_util.md | 4 ++++ test.js | 27 +++++++++++++++++++++++---- xlsx.flow.js | 19 +++++++++++++++---- xlsx.js | 19 +++++++++++++++---- 7 files changed, 81 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e0fba4..0d5154a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ changes may not be included if they are not expected to break existing code. ## Unreleased +* `sheet_to_json` now passes `null` values when `raw` is set to `true` +* `sheet_to_json` treats `null` stub cells as values in conjunction with `raw` + +## 0.9.5 (2017-03-22) + * `cellDates` affects parsing in non-XLSX formats ## 0.9.3 (2017-03-15) diff --git a/README.md b/README.md index f229ec5..1a00cac 100644 --- a/README.md +++ b/README.md @@ -856,6 +856,7 @@ generate different types of JS objects. The function takes an options argument: | range | from WS | Override Range (see table below) | | 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 | - `raw` only affects cells which have a format code (`.z`) field or a formatted text (`.w`) field. @@ -864,6 +865,9 @@ generate different types of JS objects. The function takes an options argument: - When `header` is not specified, the conversion will automatically disambiguate header entries by affixing `_` and a count starting at `1`. For example, if three columns have header `foo` the output fields are `foo`, `foo_1`, `foo_2` +- `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` `range` is expected to be one of: diff --git a/bits/90_utils.js b/bits/90_utils.js index 60ce446..91a27db 100644 --- a/bits/90_utils.js +++ b/bits/90_utils.js @@ -77,6 +77,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){ var val, row, range, header = 0, offset = 1, r, hdr/*:Array*/ = [], isempty, R, C, v, vv; var o = opts != null ? opts : {}; var raw = o.raw; + var defval = o.defval; if(sheet == null || sheet["!ref"] == null) return []; range = o.range != null ? o.range : sheet["!ref"]; if(o.header === 1) header = 1; @@ -119,16 +120,26 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){ } for (C = r.s.c; C <= r.e.c; ++C) { val = sheet[cols[C] + rr]; - if(val === undefined || val.t === undefined) continue; + if(val === undefined || val.t === undefined) { + if(defval === undefined) continue; + if(hdr[C] != null) { row[hdr[C]] = defval; isempty = false; } + continue; + } v = val.v; switch(val.t){ - case 'z': continue; + case 'z': if(v == null) break; continue; case 'e': continue; case 's': case 'd': case 'b': case 'n': break; default: throw new Error('unrecognized type ' + val.t); } - if(v !== undefined) { - row[hdr[C]] = raw ? v : format_cell(val,v); + if(hdr[C] != null) { + if(v == null) { + if(defval !== undefined) row[hdr[C]] = defval; + else if(raw && v === null) row[hdr[C]] = null; + else continue; + } else { + row[hdr[C]] = raw ? v : format_cell(val,v); + } isempty = false; } } diff --git a/docbits/82_util.md b/docbits/82_util.md index 474046d..f354114 100644 --- a/docbits/82_util.md +++ b/docbits/82_util.md @@ -65,6 +65,7 @@ generate different types of JS objects. The function takes an options argument: | range | from WS | Override Range (see table below) | | 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 | - `raw` only affects cells which have a format code (`.z`) field or a formatted text (`.w`) field. @@ -73,6 +74,9 @@ generate different types of JS objects. The function takes an options argument: - When `header` is not specified, the conversion will automatically disambiguate header entries by affixing `_` and a count starting at `1`. For example, if three columns have header `foo` the output fields are `foo`, `foo_1`, `foo_2` +- `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` `range` is expected to be one of: diff --git a/test.js b/test.js index c23ef72..4ffbbb1 100644 --- a/test.js +++ b/test.js @@ -1051,9 +1051,10 @@ function sheet_from_array_of_arrays(data, opts) { 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; + if(cell.v === undefined) continue; var cell_ref = X.utils.encode_cell({c:C,r:R}); - if(typeof cell.v === 'number') cell.t = 'n'; + 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]; @@ -1081,8 +1082,8 @@ describe('json output', function() { data = [ [1,2,3], [true, false, null, "sheetjs"], - ["foo","bar",new Date("2014-02-19T14:30Z"), "0.3"], - ["baz", null, "qux"] + ["foo", "bar", new Date("2014-02-19T14:30Z"), "0.3"], + ["baz", undefined, "qux"] ]; ws = sheet_from_array_of_arrays(data); }); @@ -1139,6 +1140,23 @@ describe('json output', function() { assert.throws(function() { seeker(json, [0,1,2], "baz"); }); }); }); + 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"); + assert.equal(json[2][3], "qux"); + assert.equal(json[2][2], "jimjin"); + assert.equal(json[0][3], "jimjin"); + 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); @@ -1158,6 +1176,7 @@ describe('json output', function() { var json = X.utils.sheet_to_json(_ws, {header:1, raw:true}); assert.equal(json.length, data.length); assert.equal(json[1][0], true); + assert.equal(json[1][2], null); assert.equal(json[2][1], "bar"); assert.equal(json[2][2].getTime(), new Date("2014-02-19T14:30Z").getTime()); assert.equal(json[3][2], "qux"); diff --git a/xlsx.flow.js b/xlsx.flow.js index d57c851..3b2dcc8 100644 --- a/xlsx.flow.js +++ b/xlsx.flow.js @@ -14074,6 +14074,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){ var val, row, range, header = 0, offset = 1, r, hdr/*:Array*/ = [], isempty, R, C, v, vv; var o = opts != null ? opts : {}; var raw = o.raw; + var defval = o.defval; if(sheet == null || sheet["!ref"] == null) return []; range = o.range != null ? o.range : sheet["!ref"]; if(o.header === 1) header = 1; @@ -14116,16 +14117,26 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){ } for (C = r.s.c; C <= r.e.c; ++C) { val = sheet[cols[C] + rr]; - if(val === undefined || val.t === undefined) continue; + if(val === undefined || val.t === undefined) { + if(defval === undefined) continue; + if(hdr[C] != null) { row[hdr[C]] = defval; isempty = false; } + continue; + } v = val.v; switch(val.t){ - case 'z': continue; + case 'z': if(v == null) break; continue; case 'e': continue; case 's': case 'd': case 'b': case 'n': break; default: throw new Error('unrecognized type ' + val.t); } - if(v !== undefined) { - row[hdr[C]] = raw ? v : format_cell(val,v); + if(hdr[C] != null) { + if(v == null) { + if(defval !== undefined) row[hdr[C]] = defval; + else if(raw && v === null) row[hdr[C]] = null; + else continue; + } else { + row[hdr[C]] = raw ? v : format_cell(val,v); + } isempty = false; } } diff --git a/xlsx.js b/xlsx.js index 5080233..0b2d30b 100644 --- a/xlsx.js +++ b/xlsx.js @@ -14007,6 +14007,7 @@ function sheet_to_json(sheet, opts){ var val, row, range, header = 0, offset = 1, r, hdr = [], isempty, R, C, v, vv; var o = opts != null ? opts : {}; var raw = o.raw; + var defval = o.defval; if(sheet == null || sheet["!ref"] == null) return []; range = o.range != null ? o.range : sheet["!ref"]; if(o.header === 1) header = 1; @@ -14049,16 +14050,26 @@ function sheet_to_json(sheet, opts){ } for (C = r.s.c; C <= r.e.c; ++C) { val = sheet[cols[C] + rr]; - if(val === undefined || val.t === undefined) continue; + if(val === undefined || val.t === undefined) { + if(defval === undefined) continue; + if(hdr[C] != null) { row[hdr[C]] = defval; isempty = false; } + continue; + } v = val.v; switch(val.t){ - case 'z': continue; + case 'z': if(v == null) break; continue; case 'e': continue; case 's': case 'd': case 'b': case 'n': break; default: throw new Error('unrecognized type ' + val.t); } - if(v !== undefined) { - row[hdr[C]] = raw ? v : format_cell(val,v); + if(hdr[C] != null) { + if(v == null) { + if(defval !== undefined) row[hdr[C]] = defval; + else if(raw && v === null) row[hdr[C]] = null; + else continue; + } else { + row[hdr[C]] = raw ? v : format_cell(val,v); + } isempty = false; } }