forked from sheetjs/sheetjs
		
	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:
		
							parent
							
								
									05185e13f2
								
							
						
					
					
						commit
						d3eaa62d45
					
				| @ -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
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										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) { | ||||
|  | ||||
							
								
								
									
										66
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										66
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -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
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										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; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user