forked from sheetjs/sheetjs
version bump 0.9.3: multiformat alignment
- merge cells and stubs consistency - character entity decoding - cellDates processing for other formats
This commit is contained in:
parent
d3eaa62d45
commit
ea1873e572
@ -5,7 +5,7 @@ but not limited to API changes and file location changes. Minor behavioral
|
||||
changes may not be included if they are not expected to break existing code.
|
||||
|
||||
|
||||
## Unreleased
|
||||
## 0.9.3 (2017-03-15)
|
||||
|
||||
* XLML property names are more closely mapped to the XLSX equivalent
|
||||
* Stub cells are now cell type `z`
|
||||
|
@ -479,7 +479,7 @@ 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`.
|
||||
will not be generated; the parser `sheetStubs` option must be set to `true`.
|
||||
|
||||
### Formulae
|
||||
|
||||
|
@ -103,6 +103,8 @@ if(program.all) {
|
||||
opts.cellFormula = true;
|
||||
opts.cellNF = true;
|
||||
opts.cellStyles = true;
|
||||
opts.sheetStubs = true;
|
||||
opts.cellDates = true;
|
||||
}
|
||||
|
||||
if(program.dev) {
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.9.2';
|
||||
XLSX.version = '0.9.3';
|
||||
|
@ -40,15 +40,15 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var unescapexml/*:StringConv*/ = (function() {
|
||||
/* 22.4.2.4 bstr (Basic String) */
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
return function unescapexml(text/*:string*/)/*:string*/ {
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
};
|
||||
})();
|
||||
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text/*:string*/)/*:string*/{
|
||||
function escapexml(text/*:string*/, xml/*:?boolean*/)/*:string*/{
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
|
||||
}
|
||||
|
@ -209,6 +209,13 @@ function parse_BrtFmlaString(data, length, opts) {
|
||||
|
||||
/* [MS-XLSB] 2.4.676 BrtMergeCell */
|
||||
var parse_BrtMergeCell = parse_UncheckedRfX;
|
||||
var write_BrtMergeCell = write_UncheckedRfX;
|
||||
/* [MS-XLSB] 2.4.108 BrtBeginMergeCells */
|
||||
function write_BrtBeginMergeCells(cnt, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
o.write_shift(4, cnt);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.656 BrtHLink */
|
||||
function parse_BrtHLink(data, length, opts) {
|
||||
@ -550,7 +557,14 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
||||
write_record(ba, 'BrtEndSheetData');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx, opts, wb) {
|
||||
function write_MERGECELLS(ba, ws/*:Worksheet*/) {
|
||||
if(!ws || !ws['!merges']) return;
|
||||
write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
|
||||
ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
var r = safe_decode_range(ws['!ref'] || "A1");
|
||||
@ -569,7 +583,7 @@ function write_ws_bin(idx, opts, wb) {
|
||||
/* [SORTSTATE] */
|
||||
/* [DCON] */
|
||||
/* [USERSHVIEWS] */
|
||||
/* [MERGECELLS] */
|
||||
write_MERGECELLS(ba, ws);
|
||||
/* [BrtPhoneticInfo] */
|
||||
/* *CONDITIONALFORMATTING */
|
||||
/* [DVALS] */
|
||||
|
@ -764,6 +764,15 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
var attr = {};
|
||||
if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
|
||||
if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
|
||||
if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
|
||||
}
|
||||
}
|
||||
|
||||
var t = "", p = "";
|
||||
switch(cell.t) {
|
||||
case 'z': return "";
|
||||
@ -771,7 +780,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
|
||||
case 'e': t = 'Error'; p = BErr[cell.v]; break;
|
||||
case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break;
|
||||
default: t = 'String'; p = escapexml(cell.v||"");
|
||||
case 's': t = 'String'; p = escapexml(cell.v||""); break;
|
||||
}
|
||||
var m = '<Data ss:Type="' + t + '">' + p + '</Data>';
|
||||
|
||||
@ -781,16 +790,27 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
|
||||
if(!ws['!ref']) return "";
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ["<Row>"];
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
var skip = false;
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
break;
|
||||
}
|
||||
if(skip) continue;
|
||||
var addr = {r:R,c:C};
|
||||
var ref = encode_cell(addr), cell = ws[ref];
|
||||
row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr));
|
||||
}
|
||||
row.push("</Row>");
|
||||
o.push(row.join(""));
|
||||
if(row.length > 2) o.push(row.join(""));
|
||||
}
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -107,13 +107,15 @@ var parse_content_xml = (function() {
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
|
||||
case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']);
|
||||
if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
|
||||
q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
|
||||
default:
|
||||
if(q.t === 'string' || q.t === 'text' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']);
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
|
@ -1,21 +1,37 @@
|
||||
var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var covered_cell_xml = ' <table:covered-table-cell/>\n';
|
||||
var cell_begin = ' <table:table-cell ', cell_end = '</table:table-cell>\n';
|
||||
var vt = 'office:value-type=';
|
||||
var p_begin = '<text:p>', p_end = '</text:p>';
|
||||
var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var skip = false, mxml = "";
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" ';
|
||||
break;
|
||||
}
|
||||
if(skip) { o.push(covered_cell_xml); continue; }
|
||||
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break;
|
||||
case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break;
|
||||
case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break;
|
||||
case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break;
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
|
23
dist/xlsx.core.min.js
vendored
23
dist/xlsx.core.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.core.min.map
vendored
2
dist/xlsx.core.min.map
vendored
File diff suppressed because one or more lines are too long
24
dist/xlsx.full.min.js
vendored
24
dist/xlsx.full.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.full.min.map
vendored
2
dist/xlsx.full.min.map
vendored
File diff suppressed because one or more lines are too long
347
dist/xlsx.js
vendored
347
dist/xlsx.js
vendored
@ -5,7 +5,7 @@
|
||||
/*exported XLSX */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.9.2';
|
||||
XLSX.version = '0.9.3';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
|
||||
@ -1453,18 +1453,19 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var unescapexml = (function() {
|
||||
/* 22.4.2.4 bstr (Basic String) */
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
return function unescapexml(text) {
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
};
|
||||
})();
|
||||
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text){
|
||||
function escapexml(text, xml){
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
|
||||
}
|
||||
function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
|
||||
|
||||
/* TODO: handle codepages */
|
||||
var xlml_fixstr = (function() {
|
||||
@ -1591,6 +1592,13 @@ XMLNS.main = [
|
||||
'http://schemas.microsoft.com/office/excel/2006/2'
|
||||
];
|
||||
|
||||
var XLMLNS = ({
|
||||
'o': 'urn:schemas-microsoft-com:office:office',
|
||||
'x': 'urn:schemas-microsoft-com:office:excel',
|
||||
'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
|
||||
'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
|
||||
'html': 'http://www.w3.org/TR/REC-html40'
|
||||
});
|
||||
function read_double_le(b, idx) {
|
||||
var s = 1 - 2 * (b[idx + 7] >>> 7);
|
||||
var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
|
||||
@ -2968,10 +2976,67 @@ function xlml_set_prop(Props, tag, val) {
|
||||
/* TODO: Normalize the properties */
|
||||
switch(tag) {
|
||||
case 'Description': tag = 'Comments'; break;
|
||||
case 'Created': tag = 'CreatedDate'; break;
|
||||
case 'LastSaved': tag = 'ModifiedDate'; break;
|
||||
}
|
||||
Props[tag] = val;
|
||||
}
|
||||
|
||||
var XLMLDocumentProperties = [
|
||||
['Title', 'Title'],
|
||||
['Subject', 'Subject'],
|
||||
['Author', 'Author'],
|
||||
['Keywords', 'Keywords'],
|
||||
['Comments', 'Description'],
|
||||
['LastAuthor', 'LastAuthor'],
|
||||
['CreatedDate', 'Created', 'date'],
|
||||
['ModifiedDate', 'LastSaved', 'date'],
|
||||
['Category', 'Category'],
|
||||
['Manager', 'Manager'],
|
||||
['Company', 'Company'],
|
||||
['AppVersion', 'Version']
|
||||
];
|
||||
|
||||
/* TODO: verify */
|
||||
function xlml_write_docprops(Props) {
|
||||
var T = 'DocumentProperties';
|
||||
var o = [];
|
||||
XLMLDocumentProperties.forEach(function(p) {
|
||||
if(!Props[p[0]]) return;
|
||||
var m = Props[p[0]];
|
||||
switch(p[2]) {
|
||||
case 'date': m = new Date(m).toISOString(); break;
|
||||
}
|
||||
o.push(writetag(p[1], m));
|
||||
});
|
||||
return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
|
||||
}
|
||||
function xlml_write_custprops(Props, Custprops) {
|
||||
var T = 'CustomDocumentProperties';
|
||||
var o = [];
|
||||
if(Props) keys(Props).forEach(function(k) {
|
||||
if(!Props.hasOwnProperty(k)) return;
|
||||
for(var i = 0; i < XLMLDocumentProperties.length; ++i)
|
||||
if(k == XLMLDocumentProperties[i][0]) return;
|
||||
var m = Props[k];
|
||||
var t = "string";
|
||||
if(typeof m == 'number') { t = "float"; m = String(m); }
|
||||
else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
|
||||
else m = String(m);
|
||||
o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
|
||||
});
|
||||
if(Custprops) keys(Custprops).forEach(function(k) {
|
||||
if(!Custprops.hasOwnProperty(k)) return;
|
||||
var m = Custprops[k];
|
||||
var t = "string";
|
||||
if(typeof m == 'number') { t = "float"; m = String(m); }
|
||||
else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
|
||||
else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); }
|
||||
else m = String(m);
|
||||
o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
|
||||
});
|
||||
return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
|
||||
}
|
||||
/* [MS-DTYP] 2.3.3 FILETIME */
|
||||
/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
|
||||
/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
|
||||
@ -3735,15 +3800,56 @@ 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 */
|
||||
/* 2.5.20 2.5.249 TODO: interpret values here */
|
||||
function parse_CellStyleXF(blob, length, style) {
|
||||
var o = {};
|
||||
var a = blob.read_shift(4), b = blob.read_shift(4);
|
||||
var c = blob.read_shift(4), d = blob.read_shift(2);
|
||||
o.patternType = XLSFillPattern[c >> 26];
|
||||
|
||||
o.alc = a & 0x07;
|
||||
o.fWrap = (a >> 3) & 0x01;
|
||||
o.alcV = (a >> 4) & 0x07;
|
||||
o.fJustLast = (a >> 7) & 0x01;
|
||||
o.trot = (a >> 8) & 0xFF;
|
||||
o.cIndent = (a >> 16) & 0x0F;
|
||||
o.fShrinkToFit = (a >> 20) & 0x01;
|
||||
o.iReadOrder = (a >> 22) & 0x02;
|
||||
o.fAtrNum = (a >> 26) & 0x01;
|
||||
o.fAtrFnt = (a >> 27) & 0x01;
|
||||
o.fAtrAlc = (a >> 28) & 0x01;
|
||||
o.fAtrBdr = (a >> 29) & 0x01;
|
||||
o.fAtrPat = (a >> 30) & 0x01;
|
||||
o.fAtrProt = (a >> 31) & 0x01;
|
||||
|
||||
o.dgLeft = b & 0x0F;
|
||||
o.dgRight = (b >> 4) & 0x0F;
|
||||
o.dgTop = (b >> 8) & 0x0F;
|
||||
o.dgBottom = (b >> 12) & 0x0F;
|
||||
o.icvLeft = (b >> 16) & 0x7F;
|
||||
o.icvRight = (b >> 23) & 0x7F;
|
||||
o.grbitDiag = (b >> 30) & 0x03;
|
||||
|
||||
o.icvTop = c & 0x7F;
|
||||
o.icvBottom = (c >> 7) & 0x7F;
|
||||
o.icvDiag = (c >> 14) & 0x7F;
|
||||
o.dgDiag = (c >> 21) & 0x0F;
|
||||
|
||||
o.icvFore = d & 0x7F;
|
||||
o.icvBack = (d >> 7) & 0x7F;
|
||||
o.fsxButton = (d >> 14) & 0x01;
|
||||
return o;
|
||||
}
|
||||
function parse_CellXF(blob, length) {return parse_CellStyleXF(blob,length,0);}
|
||||
@ -4101,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;
|
||||
@ -5766,8 +5871,19 @@ var rc_to_a1 = (function(){
|
||||
};
|
||||
})();
|
||||
|
||||
/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
|
||||
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)([1-9]\d{0,5}|10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6])(?![_.\(A-Za-z0-9])/g;
|
||||
var a1_to_rc =(function(){
|
||||
return function a1_to_rc(fstr, base) {
|
||||
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5, off, str) {
|
||||
/* TODO: handle fixcol / fixrow */
|
||||
var c = decode_col($3) - base.c;
|
||||
var r = decode_row($5) - base.r;
|
||||
return $1 + "R" + (r == 0 ? "" : "[" + r + "]") + "C" + (c == 0 ? "" : "[" + c + "]");
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
|
||||
function shift_formula_str(f, delta) {
|
||||
return f.replace(crefregex, function($0, $1, $2, $3, $4, $5, off, str) {
|
||||
return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
|
||||
@ -8060,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];
|
||||
@ -8181,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;
|
||||
}
|
||||
}
|
||||
@ -8220,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) {
|
||||
@ -8333,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;
|
||||
@ -8345,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;
|
||||
@ -8636,6 +8753,13 @@ function parse_BrtFmlaString(data, length, opts) {
|
||||
|
||||
/* [MS-XLSB] 2.4.676 BrtMergeCell */
|
||||
var parse_BrtMergeCell = parse_UncheckedRfX;
|
||||
var write_BrtMergeCell = write_UncheckedRfX;
|
||||
/* [MS-XLSB] 2.4.108 BrtBeginMergeCells */
|
||||
function write_BrtBeginMergeCells(cnt, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
o.write_shift(4, cnt);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.656 BrtHLink */
|
||||
function parse_BrtHLink(data, length, opts) {
|
||||
@ -8751,7 +8875,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;
|
||||
@ -8977,6 +9101,13 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
||||
write_record(ba, 'BrtEndSheetData');
|
||||
}
|
||||
|
||||
function write_MERGECELLS(ba, ws) {
|
||||
if(!ws || !ws['!merges']) return;
|
||||
write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
|
||||
ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx, opts, wb) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
@ -8996,7 +9127,7 @@ function write_ws_bin(idx, opts, wb) {
|
||||
/* [SORTSTATE] */
|
||||
/* [DCON] */
|
||||
/* [USERSHVIEWS] */
|
||||
/* [MERGECELLS] */
|
||||
write_MERGECELLS(ba, ws);
|
||||
/* [BrtPhoneticInfo] */
|
||||
/* *CONDITIONALFORMATTING */
|
||||
/* [DVALS] */
|
||||
@ -9606,6 +9737,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") {
|
||||
@ -9748,8 +9880,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;
|
||||
@ -10275,10 +10415,109 @@ function parse_xlml(data, opts) {
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
function write_xlml(wb, opts) {
|
||||
var o = [XML_HEADER];
|
||||
function write_props_xlml(wb, opts) {
|
||||
var o = [];
|
||||
/* DocumentProperties */
|
||||
if(wb.Props) o.push(xlml_write_docprops(wb.Props));
|
||||
/* CustomDocumentProperties */
|
||||
if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops));
|
||||
return o.join("");
|
||||
}
|
||||
/* TODO */
|
||||
function write_wb_xlml(wb, opts) {
|
||||
/* OfficeDocumentSettings */
|
||||
/* ExcelWorkbook */
|
||||
return "";
|
||||
}
|
||||
/* TODO */
|
||||
function write_sty_xlml(wb, opts) {
|
||||
/* Styles */
|
||||
return "";
|
||||
}
|
||||
/* TODO */
|
||||
function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
|
||||
if(!cell || cell.v === undefined) return "<Cell></Cell>";
|
||||
|
||||
var attr = {};
|
||||
if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
|
||||
if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
|
||||
if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break;
|
||||
case 's': t = 'String'; p = escapexml(cell.v||""); break;
|
||||
}
|
||||
var m = '<Data ss:Type="' + t + '">' + p + '</Data>';
|
||||
|
||||
return writextag("Cell", m, attr);
|
||||
}
|
||||
/* TODO */
|
||||
function write_ws_xlml_table(ws, opts, idx, wb) {
|
||||
if(!ws['!ref']) return "";
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
var skip = false;
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
break;
|
||||
}
|
||||
if(skip) continue;
|
||||
var addr = {r:R,c:C};
|
||||
var ref = encode_cell(addr), cell = ws[ref];
|
||||
row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr));
|
||||
}
|
||||
row.push("</Row>");
|
||||
if(row.length > 2) o.push(row.join(""));
|
||||
}
|
||||
return o.join("");
|
||||
}
|
||||
function write_ws_xlml(idx, opts, wb) {
|
||||
var o = [];
|
||||
var s = wb.SheetNames[idx];
|
||||
var ws = wb.Sheets[s];
|
||||
|
||||
/* Table */
|
||||
var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
|
||||
if(t.length > 0) o.push("<Table>" + t + "</Table>");
|
||||
/* WorksheetOptions */
|
||||
return o.join("");
|
||||
}
|
||||
function write_xlml(wb, opts) {
|
||||
var d = [];
|
||||
d.push(write_props_xlml(wb, opts));
|
||||
d.push(write_wb_xlml(wb, opts));
|
||||
d.push(write_sty_xlml(wb, opts));
|
||||
for(var i = 0; i < wb.SheetNames.length; ++i)
|
||||
d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
|
||||
return XML_HEADER + writextag("Workbook", d.join(""), {
|
||||
'xmlns': XLMLNS.ss,
|
||||
'xmlns:o': XLMLNS.o,
|
||||
'xmlns:x': XLMLNS.x,
|
||||
'xmlns:ss': XLMLNS.ss,
|
||||
'xmlns:dt': XLMLNS.dt,
|
||||
'xmlns:html': XLMLNS.html
|
||||
});
|
||||
}
|
||||
/* [MS-OLEDS] 2.3.8 CompObjStream */
|
||||
function parse_compobj(obj) {
|
||||
var v = {};
|
||||
@ -10334,6 +10573,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 {
|
||||
@ -10590,9 +10830,9 @@ function parse_workbook(blob, options) {
|
||||
if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
|
||||
var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
|
||||
var _fe = encode_cell({r:_fr, c:_fc});
|
||||
if(shared_formulae[_fe]) temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks, opts);
|
||||
if(shared_formulae[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
|
||||
else temp_val.F = (out[_fe] || {}).F;
|
||||
} else temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks, opts);
|
||||
} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
|
||||
}
|
||||
safe_format_xf(temp_val, options, wb.opts.Date1904);
|
||||
addcell(val.cell, temp_val, options);
|
||||
@ -10604,7 +10844,7 @@ function parse_workbook(blob, options) {
|
||||
last_formula.val = val;
|
||||
temp_val = ({v:last_formula.val, ixfe:last_formula.cell.ixfe, t:'s'});
|
||||
temp_val.XF = XFs[temp_val.ixfe];
|
||||
if(options.cellFormula) temp_val.f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
|
||||
if(options.cellFormula) temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
|
||||
safe_format_xf(temp_val, options, wb.opts.Date1904);
|
||||
addcell(last_formula.cell, temp_val, options);
|
||||
last_formula = null;
|
||||
@ -10615,7 +10855,7 @@ function parse_workbook(blob, options) {
|
||||
if(options.cellFormula && out[last_cell]) {
|
||||
if(!last_formula) break; /* technically unreachable */
|
||||
if(!last_cell || !out[last_cell]) break; /* technically unreachable */
|
||||
out[last_cell].f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
|
||||
out[last_cell].f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
|
||||
out[last_cell].F = encode_range(val[0]);
|
||||
}
|
||||
} break;
|
||||
@ -10626,7 +10866,7 @@ function parse_workbook(blob, options) {
|
||||
/* TODO: capture range */
|
||||
if(!last_formula) break; /* technically unreachable */
|
||||
shared_formulae[encode_cell(last_formula.cell)]= val[0];
|
||||
(out[encode_cell(last_formula.cell)]||{}).f = stringify_formula(val[0], range, lastcell, supbooks, opts);
|
||||
(out[encode_cell(last_formula.cell)]||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
|
||||
}
|
||||
} break;
|
||||
case 'LabelSst':
|
||||
@ -10635,6 +10875,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');
|
||||
@ -10701,7 +10954,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
|
||||
@ -10716,7 +10968,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
|
||||
@ -12433,8 +12684,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);
|
||||
@ -12480,13 +12733,15 @@ var parse_content_xml = (function() {
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
|
||||
case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']);
|
||||
if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
|
||||
q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
|
||||
default:
|
||||
if(q.t === 'string' || q.t === 'text' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']);
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
@ -12496,7 +12751,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);
|
||||
@ -12769,22 +13024,38 @@ var parse_content_xml = (function() {
|
||||
})();
|
||||
var write_content_xml = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var covered_cell_xml = ' <table:covered-table-cell/>\n';
|
||||
var cell_begin = ' <table:table-cell ', cell_end = '</table:table-cell>\n';
|
||||
var vt = 'office:value-type=';
|
||||
var p_begin = '<text:p>', p_end = '</text:p>';
|
||||
var write_ws = function(ws, wb, i, opts) {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var skip = false, mxml = "";
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" ';
|
||||
break;
|
||||
}
|
||||
if(skip) { o.push(covered_cell_xml); continue; }
|
||||
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break;
|
||||
case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break;
|
||||
case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break;
|
||||
case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break;
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
@ -13039,7 +13310,7 @@ function parse_zip(zip, opts) {
|
||||
out.files = zip.files;
|
||||
}
|
||||
if(opts.bookVBA) {
|
||||
if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,dir.vba[0],true);
|
||||
if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,dir.vba[0].replace(/^\//,''),true);
|
||||
else if(dir.defaults && dir.defaults.bin === 'application/vnd.ms-office.vbaProject') out.vbaraw = getzipdata(zip,'xl/vbaProject.bin',true);
|
||||
}
|
||||
return out;
|
||||
@ -13228,7 +13499,8 @@ function writeSync(wb, opts) {
|
||||
check_wb(wb);
|
||||
var o = opts||{};
|
||||
switch(o.bookType || 'xlsx') {
|
||||
case 'xml': return write_string_type(write_xlml(wb, o), o);
|
||||
case 'xml':
|
||||
case 'xlml': return write_string_type(write_xlml(wb, o), o);
|
||||
case 'csv': return write_string_type(write_csv_str(wb, o), o);
|
||||
case 'fods': return write_string_type(write_ods(wb, o), o);
|
||||
case 'biff2': return write_binary_type(write_biff_buf(wb, o), o);
|
||||
@ -13248,6 +13520,7 @@ function writeFileSync(wb, filename, opts) {
|
||||
case '.xlsm': o.bookType = 'xlsm'; break;
|
||||
case '.xlsb': o.bookType = 'xlsb'; break;
|
||||
case '.fods': o.bookType = 'fods'; break;
|
||||
case '.xlml': o.bookType = 'xlml'; break;
|
||||
default: switch(o.file.slice(-4).toLowerCase()) {
|
||||
case '.xls': o.bookType = 'biff2'; break;
|
||||
case '.xml': o.bookType = 'xml'; break;
|
||||
@ -13321,7 +13594,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);
|
||||
@ -13376,6 +13649,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;
|
||||
@ -13442,6 +13716,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;
|
||||
|
22
dist/xlsx.min.js
vendored
22
dist/xlsx.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.min.map
vendored
2
dist/xlsx.min.map
vendored
File diff suppressed because one or more lines are too long
31
multiformat.lst
Normal file
31
multiformat.lst
Normal file
@ -0,0 +1,31 @@
|
||||
# This file controls the multiformat tests
|
||||
# Format: <basename> <ext> <ext> [ext..]
|
||||
AutoFilter .xls .xlsb .xlsx .xml
|
||||
#BlankSheetTypes .xls .xlsb .xlsx .xml
|
||||
NumberFormatCondition .xls .xlsb .xlsm .xml
|
||||
RkNumber .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
#calendar_stress_test .xls .xlsb .xlsx .xml
|
||||
cell_style_simple .xls .xlsb .xlsx .xml
|
||||
# no-csv (newline character \r vs \n)
|
||||
comments_stress_test .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
# yes-csv
|
||||
custom_properties .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
defined_names_simple .xls .xlsb .xlsx .xml
|
||||
#formula_stress_test .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
formulae_test_simple .xls .xlsb .xlsx .xml
|
||||
hyperlink_stress_test_2011 .xls .xlsb .xlsx .xml
|
||||
#large_strings .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
merge_cells .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
named_ranges_2011 .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
# no-csv (macro serialization in xml)
|
||||
number_format .xls .xlsb .xlsm .xls.xml .xlsb.xml .xlsm.xml
|
||||
number_format_entities .xls .xlsb .xlsx .xml
|
||||
# yes-csv
|
||||
pivot_table_named_range .xls .xlsb .xlsx .xml
|
||||
pivot_table_test .xls .xlsb .xlsm
|
||||
rich_text_stress .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
||||
smart_tags_2007 .xls .xlsb .xlsx .xml
|
||||
sushi .xls .xlsb .xlsx .xml
|
||||
text_and_numbers .xls .xlsb .xlsx .xml
|
||||
#time_stress_test_1 .xls .xlsb .xlsx .xml
|
||||
xlsx-stream-d-date-cell .xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.9.2",
|
||||
"version": "0.9.3",
|
||||
"author": "sheetjs",
|
||||
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS (ODS/FODS/UOS) spreadsheet parser and writer",
|
||||
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
|
||||
|
49
test.js
49
test.js
@ -866,13 +866,14 @@ describe('roundtrip features', function() {
|
||||
|
||||
describe('should preserve features', function() {
|
||||
it('merge cells', function() {
|
||||
["xlsx", "xlsb", "xlml", "ods"].forEach(function(f) {
|
||||
var wb1 = X.readFile(paths.mcxlsx);
|
||||
var wb2 = X.read(X.write(wb1, {type:'binary'}), {type:'binary'});
|
||||
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary'}),{type:'binary'});
|
||||
var m1 = wb1.Sheets.Merge['!merges'].map(X.utils.encode_range);
|
||||
var m2 = wb2.Sheets.Merge['!merges'].map(X.utils.encode_range);
|
||||
assert.equal(m1.length, m2.length);
|
||||
for(var i = 0; i < m1.length; ++i) assert.equal(m1[i], m2[i]);
|
||||
});
|
||||
for(var i = 0; i < m1.length; ++i) assert(m1.indexOf(m2[i]) > -1);
|
||||
}); });
|
||||
});
|
||||
|
||||
describe('should preserve dates', function() {
|
||||
@ -1204,3 +1205,45 @@ describe('encryption', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiformat tests', function() {
|
||||
var mfopts = opts;
|
||||
var mft = fs.readFileSync('multiformat.lst','utf-8').split("\n");
|
||||
var csv = true;
|
||||
mft.forEach(function(x) {
|
||||
if(x[0]!="#") describe('MFT ' + x, function() {
|
||||
var fil = {}, f = [], r = x.split(/\s+/);
|
||||
if(r.length < 3) return;
|
||||
it('should parse all', function() {
|
||||
for(var j = 1; j != r.length; ++j) f[j-1] = X.readFile(dir + r[0] + r[j], mfopts);
|
||||
});
|
||||
it('should have the same sheetnames', function() {
|
||||
cmparr(f.map(function(x) { return x.SheetNames; }));
|
||||
});
|
||||
it('should have the same ranges', function() {
|
||||
f[0].SheetNames.forEach(function(s) {
|
||||
var ss = f.map(function(x) { return x.Sheets[s]; });
|
||||
cmparr(ss.map(function(s) { return s['!ref']; }));
|
||||
});
|
||||
});
|
||||
it('should have the same merges', function() {
|
||||
f[0].SheetNames.forEach(function(s) {
|
||||
var ss = f.map(function(x) { return x.Sheets[s]; });
|
||||
cmparr(ss.map(function(s) { return (s['!merges']||[]).map(function(y) { return X.utils.encode_range(y); }).sort(); }));
|
||||
});
|
||||
});
|
||||
it('should have the same CSV', csv ? function() {
|
||||
cmparr(f.map(function(x) { return x.SheetNames; }));
|
||||
var names = f[0].SheetNames;
|
||||
names.forEach(function(name) {
|
||||
cmparr(f.map(function(x) { return X.utils.sheet_to_csv(x.Sheets[name]); }));
|
||||
});
|
||||
} : null);
|
||||
});
|
||||
else x.split(/\s+/).forEach(function(w) { switch(w) {
|
||||
case "no-csv": csv = false; break;
|
||||
case "yes-csv": csv = true; break;
|
||||
}});
|
||||
});
|
||||
});
|
||||
|
||||
|
82
xlsx.flow.js
82
xlsx.flow.js
@ -5,7 +5,7 @@
|
||||
/*exported XLSX */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.9.2';
|
||||
XLSX.version = '0.9.3';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
/*:: declare var cptable:any; */
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
@ -1500,15 +1500,15 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var unescapexml/*:StringConv*/ = (function() {
|
||||
/* 22.4.2.4 bstr (Basic String) */
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
return function unescapexml(text/*:string*/)/*:string*/ {
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
};
|
||||
})();
|
||||
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text/*:string*/)/*:string*/{
|
||||
function escapexml(text/*:string*/, xml/*:?boolean*/)/*:string*/{
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
|
||||
}
|
||||
@ -8806,6 +8806,13 @@ function parse_BrtFmlaString(data, length, opts) {
|
||||
|
||||
/* [MS-XLSB] 2.4.676 BrtMergeCell */
|
||||
var parse_BrtMergeCell = parse_UncheckedRfX;
|
||||
var write_BrtMergeCell = write_UncheckedRfX;
|
||||
/* [MS-XLSB] 2.4.108 BrtBeginMergeCells */
|
||||
function write_BrtBeginMergeCells(cnt, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
o.write_shift(4, cnt);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.656 BrtHLink */
|
||||
function parse_BrtHLink(data, length, opts) {
|
||||
@ -9147,7 +9154,14 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
||||
write_record(ba, 'BrtEndSheetData');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx, opts, wb) {
|
||||
function write_MERGECELLS(ba, ws/*:Worksheet*/) {
|
||||
if(!ws || !ws['!merges']) return;
|
||||
write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
|
||||
ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
var r = safe_decode_range(ws['!ref'] || "A1");
|
||||
@ -9166,7 +9180,7 @@ function write_ws_bin(idx, opts, wb) {
|
||||
/* [SORTSTATE] */
|
||||
/* [DCON] */
|
||||
/* [USERSHVIEWS] */
|
||||
/* [MERGECELLS] */
|
||||
write_MERGECELLS(ba, ws);
|
||||
/* [BrtPhoneticInfo] */
|
||||
/* *CONDITIONALFORMATTING */
|
||||
/* [DVALS] */
|
||||
@ -10484,6 +10498,15 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
var attr = {};
|
||||
if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
|
||||
if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
|
||||
if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
|
||||
}
|
||||
}
|
||||
|
||||
var t = "", p = "";
|
||||
switch(cell.t) {
|
||||
case 'z': return "";
|
||||
@ -10491,7 +10514,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
|
||||
case 'e': t = 'Error'; p = BErr[cell.v]; break;
|
||||
case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break;
|
||||
default: t = 'String'; p = escapexml(cell.v||"");
|
||||
case 's': t = 'String'; p = escapexml(cell.v||""); break;
|
||||
}
|
||||
var m = '<Data ss:Type="' + t + '">' + p + '</Data>';
|
||||
|
||||
@ -10501,16 +10524,27 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
|
||||
if(!ws['!ref']) return "";
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ["<Row>"];
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
var skip = false;
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
break;
|
||||
}
|
||||
if(skip) continue;
|
||||
var addr = {r:R,c:C};
|
||||
var ref = encode_cell(addr), cell = ws[ref];
|
||||
row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr));
|
||||
}
|
||||
row.push("</Row>");
|
||||
o.push(row.join(""));
|
||||
if(row.length > 2) o.push(row.join(""));
|
||||
}
|
||||
return o.join("");
|
||||
}
|
||||
@ -12756,13 +12790,15 @@ var parse_content_xml = (function() {
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
|
||||
case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']);
|
||||
if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
|
||||
q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
|
||||
default:
|
||||
if(q.t === 'string' || q.t === 'text' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']);
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
@ -13045,22 +13081,38 @@ var parse_content_xml = (function() {
|
||||
})();
|
||||
var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var covered_cell_xml = ' <table:covered-table-cell/>\n';
|
||||
var cell_begin = ' <table:table-cell ', cell_end = '</table:table-cell>\n';
|
||||
var vt = 'office:value-type=';
|
||||
var p_begin = '<text:p>', p_end = '</text:p>';
|
||||
var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var skip = false, mxml = "";
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" ';
|
||||
break;
|
||||
}
|
||||
if(skip) { o.push(covered_cell_xml); continue; }
|
||||
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break;
|
||||
case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break;
|
||||
case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break;
|
||||
case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break;
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
|
80
xlsx.js
80
xlsx.js
@ -5,7 +5,7 @@
|
||||
/*exported XLSX */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.9.2';
|
||||
XLSX.version = '0.9.3';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
|
||||
@ -1453,15 +1453,15 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var unescapexml = (function() {
|
||||
/* 22.4.2.4 bstr (Basic String) */
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
|
||||
return function unescapexml(text) {
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
};
|
||||
})();
|
||||
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text){
|
||||
function escapexml(text, xml){
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
|
||||
}
|
||||
@ -8753,6 +8753,13 @@ function parse_BrtFmlaString(data, length, opts) {
|
||||
|
||||
/* [MS-XLSB] 2.4.676 BrtMergeCell */
|
||||
var parse_BrtMergeCell = parse_UncheckedRfX;
|
||||
var write_BrtMergeCell = write_UncheckedRfX;
|
||||
/* [MS-XLSB] 2.4.108 BrtBeginMergeCells */
|
||||
function write_BrtBeginMergeCells(cnt, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
o.write_shift(4, cnt);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.656 BrtHLink */
|
||||
function parse_BrtHLink(data, length, opts) {
|
||||
@ -9094,6 +9101,13 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
||||
write_record(ba, 'BrtEndSheetData');
|
||||
}
|
||||
|
||||
function write_MERGECELLS(ba, ws) {
|
||||
if(!ws || !ws['!merges']) return;
|
||||
write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
|
||||
ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx, opts, wb) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
@ -9113,7 +9127,7 @@ function write_ws_bin(idx, opts, wb) {
|
||||
/* [SORTSTATE] */
|
||||
/* [DCON] */
|
||||
/* [USERSHVIEWS] */
|
||||
/* [MERGECELLS] */
|
||||
write_MERGECELLS(ba, ws);
|
||||
/* [BrtPhoneticInfo] */
|
||||
/* *CONDITIONALFORMATTING */
|
||||
/* [DVALS] */
|
||||
@ -10427,6 +10441,15 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
|
||||
var attr = {};
|
||||
if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
|
||||
if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
|
||||
if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
|
||||
}
|
||||
}
|
||||
|
||||
var t = "", p = "";
|
||||
switch(cell.t) {
|
||||
case 'z': return "";
|
||||
@ -10434,7 +10457,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
|
||||
case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
|
||||
case 'e': t = 'Error'; p = BErr[cell.v]; break;
|
||||
case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break;
|
||||
default: t = 'String'; p = escapexml(cell.v||"");
|
||||
case 's': t = 'String'; p = escapexml(cell.v||""); break;
|
||||
}
|
||||
var m = '<Data ss:Type="' + t + '">' + p + '</Data>';
|
||||
|
||||
@ -10444,16 +10467,27 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
|
||||
function write_ws_xlml_table(ws, opts, idx, wb) {
|
||||
if(!ws['!ref']) return "";
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ["<Row>"];
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
var skip = false;
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
break;
|
||||
}
|
||||
if(skip) continue;
|
||||
var addr = {r:R,c:C};
|
||||
var ref = encode_cell(addr), cell = ws[ref];
|
||||
row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr));
|
||||
}
|
||||
row.push("</Row>");
|
||||
o.push(row.join(""));
|
||||
if(row.length > 2) o.push(row.join(""));
|
||||
}
|
||||
return o.join("");
|
||||
}
|
||||
@ -12699,13 +12733,15 @@ var parse_content_xml = (function() {
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
|
||||
case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']);
|
||||
if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
|
||||
q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
|
||||
default:
|
||||
if(q.t === 'string' || q.t === 'text' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']);
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
@ -12988,22 +13024,38 @@ var parse_content_xml = (function() {
|
||||
})();
|
||||
var write_content_xml = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var covered_cell_xml = ' <table:covered-table-cell/>\n';
|
||||
var cell_begin = ' <table:table-cell ', cell_end = '</table:table-cell>\n';
|
||||
var vt = 'office:value-type=';
|
||||
var p_begin = '<text:p>', p_end = '</text:p>';
|
||||
var write_ws = function(ws, wb, i, opts) {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var skip = false, mxml = "";
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" ';
|
||||
break;
|
||||
}
|
||||
if(skip) { o.push(covered_cell_xml); continue; }
|
||||
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break;
|
||||
case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break;
|
||||
case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break;
|
||||
case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break;
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
|
Loading…
Reference in New Issue
Block a user