unify stub cells with type z

- fixes #382 h/t @jugaltheshah @pimpelsang
- fixes #333 h/t @xushuheng0623 @abhishek1234321 @mateuszkrzeszowiec
- fixes #79 h/t @volodymyrl @elad
This commit is contained in:
SheetJS 2017-03-15 04:19:02 -04:00
parent 05185e13f2
commit d3eaa62d45
13 changed files with 172 additions and 46 deletions

@ -8,6 +8,7 @@ changes may not be included if they are not expected to break existing code.
## Unreleased
* XLML property names are more closely mapped to the XLSX equivalent
* Stub cells are now cell type `z`
## 0.9.2 (2017-03-13)

@ -477,6 +477,10 @@ dates in the local timezone. js-xlsx does not correct for this error.
Type `s` is the String type. `v` should be explicitly stored as a string to
avoid possible confusion.
Type `z` represents blank stub cells. These do not have any data or type, and
are not processed by any of the core library functions. By default these cells
will not be generated; the parser `cellStubs` option must be set to `true`.
### Formulae
The A1-style formula string is stored in the `f` field. Even though different
@ -549,7 +553,7 @@ The exported `read` and `readFile` functions accept an options argument:
| cellNF | false | Save number format string to the .z field |
| cellStyles | false | Save style/theme info to the .s field |
| cellDates | false | Store dates as type `d` (default is `n`) ** |
| sheetStubs | false | Create cell objects for stub cells |
| sheetStubs | false | Create cell objects of type `z` for stub cells |
| sheetRows | 0 | If >0, read the first `sheetRows` rows ** |
| bookDeps | false | If true, parse calculation chains |
| bookFiles | false | If true, add raw files to book object ** |

@ -315,6 +315,17 @@ function parse_MulRk(blob, length) {
if(rkrecs.length != lastcol - col + 1) throw "MulRK length mismatch";
return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
}
/* 2.4.174 */
function parse_MulBlank(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
var ixfes = [];
while(blob.l < target) ixfes.push(blob.read_shift(2));
if(blob.l !== target) throw "MulBlank read error";
var lastcol = blob.read_shift(2);
if(ixfes.length != lastcol - col + 1) throw "MulBlank length mismatch";
return {r:rw, c:col, C:lastcol, ixfe:ixfes};
}
/* 2.5.20 2.5.249 TODO: interpret values here */
function parse_CellStyleXF(blob, length, style) {
@ -711,7 +722,6 @@ var parse_SXLI = parsenoop;
var parse_SXPI = parsenoop;
var parse_DocRoute = parsenoop;
var parse_RecipName = parsenoop;
var parse_MulBlank = parsenoop;
var parse_SXDI = parsenoop;
var parse_SXDB = parsenoop;
var parse_SXFDB = parsenoop;

@ -23,6 +23,7 @@ function get_cell_style(styles, cell, opts) {
}
function safe_format(p, fmtid, fillid, opts) {
if(p.t === 'z') return;
if(p.t === 'd' && typeof p.v === 'string') p.v = new Date(p.v);
try {
if(p.t === 'e') p.w = p.w || BErr[p.v];

@ -87,7 +87,7 @@ function parse_ws_xml_hlinks(s, data, rels) {
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
var addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:"stub",v:undefined};
if(!s[addr]) s[addr] = {t:"z",v:undefined};
s[addr].l = val;
}
}
@ -126,7 +126,7 @@ function write_ws_xml_cols(ws, cols)/*:string*/ {
}
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(cell.v === undefined) return "";
if(cell.v === undefined || cell.t === 'z') return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
switch(cell.t) {
@ -239,7 +239,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
/* SCHEMA IS ACTUALLY INCORRECT HERE. IF A CELL HAS NO T, EMIT "" */
if(tag.t === undefined && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "stub";
p.t = "z";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -251,7 +251,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
p.t = 'z';
}
p.v = sstr.t;
p.r = sstr.r;

@ -324,7 +324,7 @@ function parse_ws_bin(data, opts, rels, wb)/*:Worksheet*/ {
break;
case 'BrtCellBlank': if(!opts.sheetStubs) break;
p = ({t:'s',v:undefined}/*:any*/);
p = ({t:'z',v:undefined}/*:any*/);
s[encode_col(C=val[0].c) + rr] = p;
if(refguess.s.r > row.r) refguess.s.r = row.r;
if(refguess.s.c > C) refguess.s.c = C;

@ -58,6 +58,7 @@ function xlml_set_custprop(Custprops, Rn, cp, val/*:string*/) {
}
function safe_format_xlml(cell/*:Cell*/, nf, o) {
if(cell.t === 'z') return;
try {
if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
else if(nf === "General") {
@ -200,8 +201,17 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
var rr = r + (parseInt(cell.MergeDown,10)|0);
mergecells.push({s:{c:c,r:r},e:{c:cc,r:rr}});
}
++c;
if(cell.MergeAcross) c += +cell.MergeAcross;
if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
else if(cell.MergeAcross || cell.MergeDown) {
/*:: if(!cc) cc = 0; if(!rr) rr = 0; */
for(var cma = c; cma <= cc; ++cma) {
for(var cmd = r; cmd <= rr; ++cmd) {
if(cma > c || cmd > r) cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
}
}
c = cc + 1;
}
else ++c;
} else {
cell = xlml_parsexmltagobj(Rn[0]);
if(cell.Index) c = +cell.Index - 1;
@ -756,6 +766,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
var t = "", p = "";
switch(cell.t) {
case 'z': return "";
case 'n': t = 'Number'; p = String(cell.v); break;
case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
case 'e': t = 'Error'; p = BErr[cell.v]; break;

@ -53,6 +53,7 @@ function slurp(R, blob, length/*:number*/, opts) {
}
function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
if(p.t === 'z') return;
if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
if(!p.XF) return;
try {
@ -354,6 +355,19 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'Blank': if(options.sheetStubs) {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'};
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 'MulBlank': if(options.sheetStubs) {
for(var _j = val.c; _j <= val.C; ++_j) {
var _ixfe = val.ixfe[_j-val.c];
temp_val= {ixfe:_ixfe, XF:XFs[_ixfe], t:'z'};
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:_j, r:val.r}, temp_val, options);
}
} break;
case 'RString':
case 'Label': case 'BIFF2STR':
temp_val=make_cell(val.val, val.ixfe, 's');
@ -420,7 +434,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'ColInfo': break; // TODO
case 'Row': break; // TODO
case 'DBCell': break; // TODO
case 'MulBlank': break; // TODO
case 'EntExU2': break; // TODO
case 'SxView': break; // TODO
case 'Sxvd': break; // TODO
@ -435,7 +448,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'Feat': break;
case 'FeatHdr': case 'FeatHdr11': break;
case 'Feature11': case 'Feature12': case 'List12': break;
case 'Blank': break;
case 'Country': country = val; break;
case 'RecalcId': break;
case 'DefaultRowHeight': case 'DxGCol': break; // TODO: htmlify

@ -58,8 +58,10 @@ var parse_content_xml = (function() {
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
++C;
if(opts.sheetStubs) ws[encode_cell({r:R,c:C})] = {t:'z'};
break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
@ -121,7 +123,7 @@ var parse_content_xml = (function() {
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!isstub || opts.sheetStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);

@ -66,7 +66,7 @@ function safe_format_cell(cell/*:Cell*/, v/*:any*/) {
}
function format_cell(cell/*:Cell*/, v/*:any*/) {
if(cell == null || cell.t == null) return "";
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(v === undefined) return safe_format_cell(cell, cell.v);
return safe_format_cell(cell, v);
@ -121,6 +121,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
if(val === undefined || val.t === undefined) continue;
v = val.v;
switch(val.t){
case 'z': continue;
case 'e': continue;
case 's': break;
case 'b': case 'n': break;
@ -187,6 +188,7 @@ function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
if(y.indexOf(":") == -1) y = y + ":" + y;
}
if(x.f != null) val = x.f;
else if(x.t == 'z') continue;
else if(x.t == 'n' && x.v != null) val = "" + x.v;
else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
else if(x.w !== undefined) val = "'" + x.w;

14
test.js

@ -346,10 +346,18 @@ describe('parse options', function() {
});
});
it('should generate sheet stubs when requested', function() {
/* TODO: ODS/XLS/XML */
[paths.mcxlsx, paths.mcxlsb /*, paths.mcods, paths.mcxls, paths.mcxml*/].forEach(function(p) {
[paths.mcxlsx, paths.mcxlsb, paths.mcods, paths.mcxls, paths.mcxml].forEach(function(p) {
var wb = X.readFile(p, {sheetStubs:true});
assert(typeof wb.Sheets.Merge.A2.t !== 'undefined');
assert(wb.Sheets.Merge.A2.t == 'z');
});
});
it('should handle stub cells', function() {
[paths.mcxlsx, paths.mcxlsb, paths.mcods, paths.mcxls, paths.mcxml].forEach(function(p) {
var wb = X.readFile(p, {sheetStubs:true});
X.utils.sheet_to_csv(wb.Sheets.Merge);
X.utils.sheet_to_json(wb.Sheets.Merge);
X.utils.sheet_to_formulae(wb.Sheets.Merge);
ofmt.forEach(function(f) { X.write(wb, {type:"binary", bookType:f}); });
});
});
function checkcells(wb, A46, B26, C16, D2) {

@ -3852,6 +3852,17 @@ function parse_MulRk(blob, length) {
if(rkrecs.length != lastcol - col + 1) throw "MulRK length mismatch";
return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
}
/* 2.4.174 */
function parse_MulBlank(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
var ixfes = [];
while(blob.l < target) ixfes.push(blob.read_shift(2));
if(blob.l !== target) throw "MulBlank read error";
var lastcol = blob.read_shift(2);
if(ixfes.length != lastcol - col + 1) throw "MulBlank length mismatch";
return {r:rw, c:col, C:lastcol, ixfe:ixfes};
}
/* 2.5.20 2.5.249 TODO: interpret values here */
function parse_CellStyleXF(blob, length, style) {
@ -4248,7 +4259,6 @@ var parse_SXLI = parsenoop;
var parse_SXPI = parsenoop;
var parse_DocRoute = parsenoop;
var parse_RecipName = parsenoop;
var parse_MulBlank = parsenoop;
var parse_SXDI = parsenoop;
var parse_SXDB = parsenoop;
var parse_SXFDB = parsenoop;
@ -8219,6 +8229,7 @@ function get_cell_style(styles, cell, opts) {
}
function safe_format(p, fmtid, fillid, opts) {
if(p.t === 'z') return;
if(p.t === 'd' && typeof p.v === 'string') p.v = new Date(p.v);
try {
if(p.t === 'e') p.w = p.w || BErr[p.v];
@ -8340,7 +8351,7 @@ function parse_ws_xml_hlinks(s, data, rels) {
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
var addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:"stub",v:undefined};
if(!s[addr]) s[addr] = {t:"z",v:undefined};
s[addr].l = val;
}
}
@ -8379,7 +8390,7 @@ function write_ws_xml_cols(ws, cols)/*:string*/ {
}
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(cell.v === undefined) return "";
if(cell.v === undefined || cell.t === 'z') return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
switch(cell.t) {
@ -8492,7 +8503,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
/* SCHEMA IS ACTUALLY INCORRECT HERE. IF A CELL HAS NO T, EMIT "" */
if(tag.t === undefined && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "stub";
p.t = "z";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -8504,7 +8515,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
p.t = 'z';
}
p.v = sstr.t;
p.r = sstr.r;
@ -8910,7 +8921,7 @@ function parse_ws_bin(data, opts, rels, wb)/*:Worksheet*/ {
break;
case 'BrtCellBlank': if(!opts.sheetStubs) break;
p = ({t:'s',v:undefined}/*:any*/);
p = ({t:'z',v:undefined}/*:any*/);
s[encode_col(C=val[0].c) + rr] = p;
if(refguess.s.r > row.r) refguess.s.r = row.r;
if(refguess.s.c > C) refguess.s.c = C;
@ -9767,6 +9778,7 @@ function xlml_set_custprop(Custprops, Rn, cp, val/*:string*/) {
}
function safe_format_xlml(cell/*:Cell*/, nf, o) {
if(cell.t === 'z') return;
try {
if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
else if(nf === "General") {
@ -9909,8 +9921,17 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
var rr = r + (parseInt(cell.MergeDown,10)|0);
mergecells.push({s:{c:c,r:r},e:{c:cc,r:rr}});
}
++c;
if(cell.MergeAcross) c += +cell.MergeAcross;
if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
else if(cell.MergeAcross || cell.MergeDown) {
/*:: if(!cc) cc = 0; if(!rr) rr = 0; */
for(var cma = c; cma <= cc; ++cma) {
for(var cmd = r; cmd <= rr; ++cmd) {
if(cma > c || cmd > r) cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
}
}
c = cc + 1;
}
else ++c;
} else {
cell = xlml_parsexmltagobj(Rn[0]);
if(cell.Index) c = +cell.Index - 1;
@ -10465,6 +10486,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
var t = "", p = "";
switch(cell.t) {
case 'z': return "";
case 'n': t = 'Number'; p = String(cell.v); break;
case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
case 'e': t = 'Error'; p = BErr[cell.v]; break;
@ -10574,6 +10596,7 @@ function slurp(R, blob, length/*:number*/, opts) {
}
function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
if(p.t === 'z') return;
if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
if(!p.XF) return;
try {
@ -10875,6 +10898,19 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'Blank': if(options.sheetStubs) {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'};
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 'MulBlank': if(options.sheetStubs) {
for(var _j = val.c; _j <= val.C; ++_j) {
var _ixfe = val.ixfe[_j-val.c];
temp_val= {ixfe:_ixfe, XF:XFs[_ixfe], t:'z'};
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:_j, r:val.r}, temp_val, options);
}
} break;
case 'RString':
case 'Label': case 'BIFF2STR':
temp_val=make_cell(val.val, val.ixfe, 's');
@ -10941,7 +10977,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'ColInfo': break; // TODO
case 'Row': break; // TODO
case 'DBCell': break; // TODO
case 'MulBlank': break; // TODO
case 'EntExU2': break; // TODO
case 'SxView': break; // TODO
case 'Sxvd': break; // TODO
@ -10956,7 +10991,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'Feat': break;
case 'FeatHdr': case 'FeatHdr11': break;
case 'Feature11': case 'Feature12': case 'List12': break;
case 'Blank': break;
case 'Country': country = val; break;
case 'RecalcId': break;
case 'DefaultRowHeight': case 'DxGCol': break; // TODO: htmlify
@ -12673,8 +12707,10 @@ var parse_content_xml = (function() {
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
++C;
if(opts.sheetStubs) ws[encode_cell({r:R,c:C})] = {t:'z'};
break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
@ -12736,7 +12772,7 @@ var parse_content_xml = (function() {
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!isstub || opts.sheetStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);
@ -13571,7 +13607,7 @@ function safe_format_cell(cell/*:Cell*/, v/*:any*/) {
}
function format_cell(cell/*:Cell*/, v/*:any*/) {
if(cell == null || cell.t == null) return "";
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(v === undefined) return safe_format_cell(cell, cell.v);
return safe_format_cell(cell, v);
@ -13626,6 +13662,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){
if(val === undefined || val.t === undefined) continue;
v = val.v;
switch(val.t){
case 'z': continue;
case 'e': continue;
case 's': break;
case 'b': case 'n': break;
@ -13692,6 +13729,7 @@ function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
if(y.indexOf(":") == -1) y = y + ":" + y;
}
if(x.f != null) val = x.f;
else if(x.t == 'z') continue;
else if(x.t == 'n' && x.v != null) val = "" + x.v;
else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
else if(x.w !== undefined) val = "'" + x.w;

65
xlsx.js

@ -3800,6 +3800,17 @@ function parse_MulRk(blob, length) {
if(rkrecs.length != lastcol - col + 1) throw "MulRK length mismatch";
return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
}
/* 2.4.174 */
function parse_MulBlank(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
var ixfes = [];
while(blob.l < target) ixfes.push(blob.read_shift(2));
if(blob.l !== target) throw "MulBlank read error";
var lastcol = blob.read_shift(2);
if(ixfes.length != lastcol - col + 1) throw "MulBlank length mismatch";
return {r:rw, c:col, C:lastcol, ixfe:ixfes};
}
/* 2.5.20 2.5.249 TODO: interpret values here */
function parse_CellStyleXF(blob, length, style) {
@ -4196,7 +4207,6 @@ var parse_SXLI = parsenoop;
var parse_SXPI = parsenoop;
var parse_DocRoute = parsenoop;
var parse_RecipName = parsenoop;
var parse_MulBlank = parsenoop;
var parse_SXDI = parsenoop;
var parse_SXDB = parsenoop;
var parse_SXFDB = parsenoop;
@ -8166,6 +8176,7 @@ function get_cell_style(styles, cell, opts) {
}
function safe_format(p, fmtid, fillid, opts) {
if(p.t === 'z') return;
if(p.t === 'd' && typeof p.v === 'string') p.v = new Date(p.v);
try {
if(p.t === 'e') p.w = p.w || BErr[p.v];
@ -8287,7 +8298,7 @@ function parse_ws_xml_hlinks(s, data, rels) {
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
var addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:"stub",v:undefined};
if(!s[addr]) s[addr] = {t:"z",v:undefined};
s[addr].l = val;
}
}
@ -8326,7 +8337,7 @@ function write_ws_xml_cols(ws, cols) {
}
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(cell.v === undefined) return "";
if(cell.v === undefined || cell.t === 'z') return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
switch(cell.t) {
@ -8439,7 +8450,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
/* SCHEMA IS ACTUALLY INCORRECT HERE. IF A CELL HAS NO T, EMIT "" */
if(tag.t === undefined && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "stub";
p.t = "z";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -8451,7 +8462,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
p.t = 'z';
}
p.v = sstr.t;
p.r = sstr.r;
@ -8857,7 +8868,7 @@ function parse_ws_bin(data, opts, rels, wb) {
break;
case 'BrtCellBlank': if(!opts.sheetStubs) break;
p = ({t:'s',v:undefined});
p = ({t:'z',v:undefined});
s[encode_col(C=val[0].c) + rr] = p;
if(refguess.s.r > row.r) refguess.s.r = row.r;
if(refguess.s.c > C) refguess.s.c = C;
@ -9712,6 +9723,7 @@ function xlml_set_custprop(Custprops, Rn, cp, val) {
}
function safe_format_xlml(cell, nf, o) {
if(cell.t === 'z') return;
try {
if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
else if(nf === "General") {
@ -9854,8 +9866,16 @@ function parse_xlml_xml(d, opts) {
var rr = r + (parseInt(cell.MergeDown,10)|0);
mergecells.push({s:{c:c,r:r},e:{c:cc,r:rr}});
}
++c;
if(cell.MergeAcross) c += +cell.MergeAcross;
if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
else if(cell.MergeAcross || cell.MergeDown) {
for(var cma = c; cma <= cc; ++cma) {
for(var cmd = r; cmd <= rr; ++cmd) {
if(cma > c || cmd > r) cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
}
}
c = cc + 1;
}
else ++c;
} else {
cell = xlml_parsexmltagobj(Rn[0]);
if(cell.Index) c = +cell.Index - 1;
@ -10409,6 +10429,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
var t = "", p = "";
switch(cell.t) {
case 'z': return "";
case 'n': t = 'Number'; p = String(cell.v); break;
case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
case 'e': t = 'Error'; p = BErr[cell.v]; break;
@ -10518,6 +10539,7 @@ function slurp(R, blob, length, opts) {
}
function safe_format_xf(p, opts, date1904) {
if(p.t === 'z') return;
if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
if(!p.XF) return;
try {
@ -10819,6 +10841,19 @@ function parse_workbook(blob, options) {
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'Blank': if(options.sheetStubs) {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'};
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 'MulBlank': if(options.sheetStubs) {
for(var _j = val.c; _j <= val.C; ++_j) {
var _ixfe = val.ixfe[_j-val.c];
temp_val= {ixfe:_ixfe, XF:XFs[_ixfe], t:'z'};
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:_j, r:val.r}, temp_val, options);
}
} break;
case 'RString':
case 'Label': case 'BIFF2STR':
temp_val=make_cell(val.val, val.ixfe, 's');
@ -10885,7 +10920,6 @@ function parse_workbook(blob, options) {
case 'ColInfo': break; // TODO
case 'Row': break; // TODO
case 'DBCell': break; // TODO
case 'MulBlank': break; // TODO
case 'EntExU2': break; // TODO
case 'SxView': break; // TODO
case 'Sxvd': break; // TODO
@ -10900,7 +10934,6 @@ function parse_workbook(blob, options) {
case 'Feat': break;
case 'FeatHdr': case 'FeatHdr11': break;
case 'Feature11': case 'Feature12': case 'List12': break;
case 'Blank': break;
case 'Country': country = val; break;
case 'RecalcId': break;
case 'DefaultRowHeight': case 'DxGCol': break; // TODO: htmlify
@ -12617,8 +12650,10 @@ var parse_content_xml = (function() {
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
++C;
if(opts.sheetStubs) ws[encode_cell({r:R,c:C})] = {t:'z'};
break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
@ -12680,7 +12715,7 @@ var parse_content_xml = (function() {
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!isstub || opts.sheetStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);
@ -13507,7 +13542,7 @@ function safe_format_cell(cell, v) {
}
function format_cell(cell, v) {
if(cell == null || cell.t == null) return "";
if(cell == null || cell.t == null || cell.t == 'z') return "";
if(cell.w !== undefined) return cell.w;
if(v === undefined) return safe_format_cell(cell, cell.v);
return safe_format_cell(cell, v);
@ -13562,6 +13597,7 @@ function sheet_to_json(sheet, opts){
if(val === undefined || val.t === undefined) continue;
v = val.v;
switch(val.t){
case 'z': continue;
case 'e': continue;
case 's': break;
case 'b': case 'n': break;
@ -13628,6 +13664,7 @@ function sheet_to_formulae(sheet) {
if(y.indexOf(":") == -1) y = y + ":" + y;
}
if(x.f != null) val = x.f;
else if(x.t == 'z') continue;
else if(x.t == 'n' && x.v != null) val = "" + x.v;
else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
else if(x.w !== undefined) val = "'" + x.w;