version bump 0.7.11: ODS hooks
- ODS hooks + very basic parser (ods.js) - handle implicit row/col spec (h/t @EarlJS, see http://git.io/2lwOuA)
This commit is contained in:
parent
5942587509
commit
61d2e55cc6
|
@ -21,3 +21,5 @@ test.js
|
|||
.jscs.json
|
||||
.gitmodules
|
||||
.travis.yml
|
||||
bits/
|
||||
odsbits/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "0.10.30"
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
before_install:
|
||||
- "npm install -g mocha"
|
||||
|
|
32
Makefile
32
Makefile
|
@ -1,15 +1,21 @@
|
|||
LIB=xlsx
|
||||
DEPS=$(sort $(wildcard bits/*.js))
|
||||
TARGET=$(LIB).js
|
||||
FMT=xlsx xlsm xlsb misc full
|
||||
FMT=xlsx xlsm xlsb ods misc full
|
||||
REQS=jszip.js
|
||||
ADDONS=dist/cpexcel.js
|
||||
AUXTARGETS=ods.js
|
||||
|
||||
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
|
||||
DEPS=$(sort $(wildcard bits/*.js))
|
||||
TARGET=$(LIB).js
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET) $(AUXTARGETS)
|
||||
|
||||
$(TARGET): $(DEPS)
|
||||
cat $^ | tr -d '\15\32' > $@
|
||||
|
||||
bits/01_version.js: package.json
|
||||
echo "XLSX.version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
|
||||
echo "$(ULIB).version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
@ -45,8 +51,8 @@ $(TESTFMT): test_%:
|
|||
|
||||
.PHONY: lint
|
||||
lint: $(TARGET)
|
||||
jshint --show-non-errors $(TARGET)
|
||||
jscs $(TARGET)
|
||||
jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
jscs $(TARGET) $(AUXTARGETS)
|
||||
|
||||
.PHONY: test-osx
|
||||
test-osx:
|
||||
|
@ -85,7 +91,19 @@ dist: dist-deps $(TARGET) bower.json
|
|||
uglifyjs $(REQS) $(TARGET) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)"
|
||||
uglifyjs $(REQS) $(ADDONS) $(TARGET) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
|
||||
|
||||
.PHONY: aux
|
||||
aux: $(AUXTARGETS)
|
||||
|
||||
.PHONY: ods
|
||||
ods: ods.js
|
||||
|
||||
ODSDEPS=$(sort $(wildcard odsbits/*.js))
|
||||
ods.js: $(ODSDEPS)
|
||||
cat $(ODSDEPS) | tr -d '\15\32' > $@
|
||||
cp ods.js dist/ods.js
|
||||
|
||||
.PHONY: dist-deps
|
||||
dist-deps:
|
||||
dist-deps: ods.js
|
||||
cp node_modules/codepage/dist/cpexcel.full.js dist/cpexcel.js
|
||||
cp jszip.js dist/jszip.js
|
||||
cp ods.js dist/ods.js
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# xlsx
|
||||
|
||||
Parser and writer for Excel 2007+ (XLSX/XLSM/XLSB) files. Pure-JS cleanroom
|
||||
implementation from the Office Open XML spec, [MS-XLSB], and related documents.
|
||||
Parser and writer for Excel 2007+ (XLSX/XLSM/XLSB) files and parser for ODS files.
|
||||
Pure-JS cleanroom implementation from the Office Open XML spec, [MS-XLSB], and related documents.
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -36,6 +36,8 @@ be included directly:
|
|||
|
||||
<!-- international support from https://github.com/sheetjs/js-codepage -->
|
||||
<script src="dist/cpexcel.js"></script>
|
||||
<!-- ODS support -->
|
||||
<script src="dist/ods.js"></script>
|
||||
|
||||
An appropriate version for each dependency is included in the dist/ directory.
|
||||
|
||||
|
@ -458,6 +460,9 @@ OSP-covered specifications:
|
|||
- [MS-OE376]: Office Implementation Information for ECMA-376 Standards Support
|
||||
- [MS-XLDM]: Spreadsheet Data Model File Format
|
||||
|
||||
Open Document Format for Office Applications Version 1.2 (29 September 2011)
|
||||
|
||||
|
||||
## Badges
|
||||
|
||||
[![Build Status](https://travis-ci.org/SheetJS/js-xlsx.svg?branch=master)](https://travis-ci.org/SheetJS/js-xlsx)
|
||||
|
|
|
@ -1 +1 @@
|
|||
XLSX.version = '0.7.10';
|
||||
XLSX.version = '0.7.11';
|
||||
|
|
|
@ -13,11 +13,17 @@ function getdata(data) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
throw new Error("Cannot find file " + file + " in zip");
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
|
|
|
@ -148,13 +148,13 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
|
|||
}
|
||||
|
||||
var parse_ws_xml_data = (function parse_ws_xml_data_factory() {
|
||||
var cellregex = /<(?:\w+:)?c /, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var rregex = /r=["']([^"']*)["']/, isregex = /<is>([\S\s]*?)<\/is>/;
|
||||
var match_v = matchtag("v"), match_f = matchtag("f");
|
||||
|
||||
return function parse_ws_xml_data(sdata, s, opts, guess) {
|
||||
var ri = 0, x = "", cells = [], cref = [], idx = 0, i=0, cc=0, d="", p;
|
||||
var tag;
|
||||
var tag, tagr = 0, tagc = 0;
|
||||
var sstr;
|
||||
var fmtid = 0, fillid = 0, do_format = Array.isArray(styles.CellXf), cf;
|
||||
for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
|
||||
|
@ -165,18 +165,19 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
|
|||
/* 18.3.1.73 row CT_Row */
|
||||
for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
|
||||
tag = parsexmltag(x.substr(0,ri), true);
|
||||
var tagr = parseInt(tag.r, 10);
|
||||
/* SpreadSheetGear uses implicit r/c */
|
||||
tagr = typeof tag.r !== 'undefined' ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
|
||||
if(opts.sheetRows && opts.sheetRows < tagr) continue;
|
||||
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
|
||||
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
|
||||
|
||||
/* 18.3.1.4 c CT_Cell */
|
||||
cells = x.substr(ri).split(cellregex);
|
||||
for(ri = 1; ri != cells.length; ++ri) {
|
||||
for(ri = typeof tag.r === 'undefined' ? 0 : 1; ri != cells.length; ++ri) {
|
||||
x = cells[ri].trim();
|
||||
if(x.length === 0) continue;
|
||||
cref = x.match(rregex); idx = ri; i=0; cc=0;
|
||||
x = "<c " + x;
|
||||
x = "<c " + (x.substr(0,1)=="<"?">":"") + x;
|
||||
if(cref !== null && cref.length === 2) {
|
||||
idx = 0; d=cref[1];
|
||||
for(i=0; i != d.length; ++i) {
|
||||
|
@ -184,10 +185,11 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
|
|||
idx = 26*idx + cc;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
|
||||
tagc = idx;
|
||||
} else ++tagc;
|
||||
for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
|
||||
tag = parsexmltag(x.substr(0,i), true);
|
||||
if(!tag.r) tag.r = utils.encode_cell({r:tagr-1, c:tagc});
|
||||
d = x.substr(i);
|
||||
p = {t:""};
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/* Helper function to call out to ODS parser */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./dist/od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
|
@ -19,6 +19,10 @@ function parse_zip(zip, opts) {
|
|||
opts = opts || {};
|
||||
fix_read_opts(opts);
|
||||
reset_cp();
|
||||
|
||||
/* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
|
||||
if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
|
||||
|
||||
var entries = keys(zip.files).filter(nodirs).sort();
|
||||
var dir = parse_ct(getzipdata(zip, '[Content_Types].xml'), opts);
|
||||
var xlsb = false;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "js-xlsx",
|
||||
"homepage": "https://github.com/SheetJS/js-xlsx",
|
||||
"main": "dist/xlsx.js",
|
||||
"version": "0.7.10",
|
||||
"version": "0.7.11",
|
||||
"ignore": [
|
||||
"bin",
|
||||
"bits",
|
||||
|
@ -14,6 +14,7 @@
|
|||
"xlsx",
|
||||
"xlsm",
|
||||
"xlsb",
|
||||
"ods",
|
||||
"js-xlsx"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
/* ods.js (C) 2014 SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint -W041 */
|
||||
var ODS = {};
|
||||
(function make_ods(ODS) {
|
||||
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
|
||||
var get_utils = function() {
|
||||
if(typeof XLSX !== 'undefined') return XLSX.utils;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') return require('xl' + 'sx').utils;
|
||||
throw new Error("Cannot find XLSX utils");
|
||||
};
|
||||
var has_buf = (typeof Buffer !== 'undefined');
|
||||
function getdata(data) {
|
||||
if(!data) return null;
|
||||
if(data.data) return data.data;
|
||||
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
|
||||
if(data.asBinary) return data.asBinary();
|
||||
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
|
||||
return null;
|
||||
}
|
||||
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
if(!safe) return getdata(getzipfile(zip, file));
|
||||
if(!file) return null;
|
||||
try { return getzipdata(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
var _fs, jszip;
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
if(has_buf && typeof jszip === 'undefined') jszip = require('js'+'zip');
|
||||
if(typeof jszip === 'undefined') jszip = require('./js'+'zip').JSZip;
|
||||
_fs = require('f'+'s');
|
||||
}
|
||||
}
|
||||
var attregexg=/\b[\w:-]+=["'][^"]*['"]/g;
|
||||
var tagregex=/<[^>]*>/g;
|
||||
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
|
||||
function parsexmltag(tag, skip_root) {
|
||||
var z = [];
|
||||
var eq = 0, c = 0;
|
||||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
|
||||
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
|
||||
if(j===q.length) z[q] = v;
|
||||
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
|
||||
|
||||
var encodings = {
|
||||
'"': '"',
|
||||
''': "'",
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencoding = {
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencstr = "&<>'\"".split("");
|
||||
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]+)_/g;
|
||||
function unescapexml(text){
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
}
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text){
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value, tag) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function datenum(v) {
|
||||
var epoch = Date.parse(v);
|
||||
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
/* ISO 8601 Duration */
|
||||
function parse_isodur(s) {
|
||||
var sec = 0, mt = 0, time = false;
|
||||
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
|
||||
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
|
||||
for(var i = 1; i != m.length; ++i) {
|
||||
if(!m[i]) continue;
|
||||
mt = 1;
|
||||
if(i > 3) time = true;
|
||||
switch(m[i].substr(m[i].length-1)) {
|
||||
case 'Y':
|
||||
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
|
||||
case 'D': mt *= 24;
|
||||
/* falls through */
|
||||
case 'H': mt *= 60;
|
||||
/* falls through */
|
||||
case 'M':
|
||||
if(!time) throw new Error("Unsupported ISO Duration Field: M");
|
||||
else mt *= 60;
|
||||
/* falls through */
|
||||
case 'S': break;
|
||||
}
|
||||
sec += mt * parseInt(m[i], 10);
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
if(typeof d === 'string') return d;
|
||||
throw "badf";
|
||||
}
|
||||
|
||||
var xlmlregex = /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/mg;
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
var parse_manifest = function(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0]);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
case 'algorithm': // 4.5 <manifest:algorithm>
|
||||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: throw Rn;
|
||||
}
|
||||
};
|
||||
var parse_text_p = function(text, tag) {
|
||||
return text;
|
||||
};
|
||||
var parse_content_xml = (function() {
|
||||
|
||||
var number_formats = {
|
||||
/* ods name: [short ssf fmt, long ssf fmt] */
|
||||
day: ["d", "dd"],
|
||||
month: ["m", "mm"],
|
||||
year: ["y", "yy"],
|
||||
hours: ["h", "hh"],
|
||||
minutes: ["m", "mm"],
|
||||
seconds: ["s", "ss"],
|
||||
"am-pm": ["A/P", "AM/PM"],
|
||||
"day-of-week": ["ddd", "dddd"]
|
||||
};
|
||||
|
||||
return function pcx(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var state = [], tmp;
|
||||
var tag;
|
||||
var NFtag, NF, pidx;
|
||||
var sheetag;
|
||||
var Sheets = {}, SheetNames = [], ws = {};
|
||||
var Rn, q;
|
||||
var ctag;
|
||||
var textp, textpidx, textptag;
|
||||
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0]);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'table-row':
|
||||
if(Rn[1] === '/') break;
|
||||
++R; C = -1; break; // 9.1.3 <table:table-row>
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') { ++C; break; } /* stub */
|
||||
if(Rn[1]!=='/') {
|
||||
++C;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
q = {t:ctag['value-type'], v:null};
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'string': q.t = 'str'; break;
|
||||
default: throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 'str') q.v = textp;
|
||||
if(textp) q.w = textp;
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
q = null;
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
case 'document-content': // 3.1.3.2 <office:document-content>
|
||||
case 'spreadsheet': // 3.7 <office:spreadsheet>
|
||||
case 'scripts': // 3.12 <office:scripts>
|
||||
case 'font-face-decls': // 3.14 <office:font-face-decls>
|
||||
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
|
||||
break;
|
||||
|
||||
case 'number-style': // 16.27.2 <number:number-style>
|
||||
case 'percentage-style': // 16.27.9 <number:percentage-style>
|
||||
case 'date-style': // 16.27.10 <number:date-style>
|
||||
case 'time-style': // 16.27.18 <number:time-style>
|
||||
if(Rn[1]==='/'){
|
||||
number_format_map[NFtag.name] = NF;
|
||||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0]);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
case 'script': break; // 3.13 <office:script>
|
||||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
case 'table-properties': break; // 17.15 <style:table-properties>
|
||||
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
|
||||
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
|
||||
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
|
||||
|
||||
case 'number': // 16.27.3 <number:number>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
case 'era': // 16.27.14 <number:era>
|
||||
case 'day-of-week': // 16.27.15 <number:day-of-week>
|
||||
case 'week-of-year': // 16.27.16 <number:week-of-year>
|
||||
case 'quarter': // 16.27.17 <number:quarter>
|
||||
case 'hours': // 16.27.19 <number:hours>
|
||||
case 'minutes': // 16.27.20 <number:minutes>
|
||||
case 'seconds': // 16.27.21 <number:seconds>
|
||||
case 'am-pm': // 16.27.22 <number:am-pm>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
|
||||
case 'boolean': break; // 16.27.24 <number:boolean>
|
||||
case 'text-style': break; // 16.27.25 <number:text-style>
|
||||
case 'text': // 16.27.26 <number:text>
|
||||
if(Rn[0].substr(-2) === "/>") break;
|
||||
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
|
||||
case 'number-style':
|
||||
case 'date-style':
|
||||
case 'time-style':
|
||||
NF += str.slice(pidx, Rn.index);
|
||||
break;
|
||||
}
|
||||
else pidx = Rn.index + Rn[0].length;
|
||||
break;
|
||||
case 'text-content': break; // 16.27.27 <number:text-content>
|
||||
case 'text-properties': break; // 16.27.27 <style:text-properties>
|
||||
|
||||
case 'body': break; // 3.3 16.9.6 19.726.3
|
||||
|
||||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'graphic-properties': break;
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.11 <table:named-range>
|
||||
case 'span': break; // <text:span>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0]); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
case 'annotation': break;
|
||||
default: throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
SheetNames: SheetNames
|
||||
};
|
||||
return out;
|
||||
};
|
||||
})();
|
||||
/* Part 3: Packages */
|
||||
var parse_ods = function(zip, opts) {
|
||||
//var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'));
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'));
|
||||
};
|
||||
ODS.parse_ods = parse_ods;
|
||||
})(typeof exports !== 'undefined' ? exports : ODS);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -3,7 +3,7 @@
|
|||
/*jshint -W041 */
|
||||
var XLSX = {};
|
||||
(function(XLSX){
|
||||
XLSX.version = '0.7.10';
|
||||
XLSX.version = '0.7.11';
|
||||
var current_codepage = 1252, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
|
@ -847,11 +847,17 @@ function getdata(data) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
throw new Error("Cannot find file " + file + " in zip");
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
|
@ -2934,13 +2940,13 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
|
|||
}
|
||||
|
||||
var parse_ws_xml_data = (function parse_ws_xml_data_factory() {
|
||||
var cellregex = /<(?:\w+:)?c /, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var rregex = /r=["']([^"']*)["']/, isregex = /<is>([\S\s]*?)<\/is>/;
|
||||
var match_v = matchtag("v"), match_f = matchtag("f");
|
||||
|
||||
return function parse_ws_xml_data(sdata, s, opts, guess) {
|
||||
var ri = 0, x = "", cells = [], cref = [], idx = 0, i=0, cc=0, d="", p;
|
||||
var tag;
|
||||
var tag, tagr = 0, tagc = 0;
|
||||
var sstr;
|
||||
var fmtid = 0, fillid = 0, do_format = Array.isArray(styles.CellXf), cf;
|
||||
for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
|
||||
|
@ -2951,18 +2957,19 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
|
|||
/* 18.3.1.73 row CT_Row */
|
||||
for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
|
||||
tag = parsexmltag(x.substr(0,ri), true);
|
||||
var tagr = parseInt(tag.r, 10);
|
||||
/* SpreadSheetGear uses implicit r/c */
|
||||
tagr = typeof tag.r !== 'undefined' ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
|
||||
if(opts.sheetRows && opts.sheetRows < tagr) continue;
|
||||
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
|
||||
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
|
||||
|
||||
/* 18.3.1.4 c CT_Cell */
|
||||
cells = x.substr(ri).split(cellregex);
|
||||
for(ri = 1, cellen = cells.length; ri != cellen; ++ri) {
|
||||
for(ri = typeof tag.r === 'undefined' ? 0 : 1; ri != cells.length; ++ri) {
|
||||
x = cells[ri].trim();
|
||||
if(x.length === 0) continue;
|
||||
cref = x.match(rregex); idx = ri; i=0; cc=0;
|
||||
x = "<c " + x;
|
||||
x = "<c " + (x.substr(0,1)=="<"?">":"") + x;
|
||||
if(cref !== null && cref.length === 2) {
|
||||
idx = 0; d=cref[1];
|
||||
for(i=0; i != d.length; ++i) {
|
||||
|
@ -2970,10 +2977,11 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
|
|||
idx = 26*idx + cc;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
|
||||
tagc = idx;
|
||||
} else ++tagc;
|
||||
for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
|
||||
tag = parsexmltag(x.substr(0,i), true);
|
||||
if(!tag.r) tag.r = utils.encode_cell({r:tagr-1, c:tagc});
|
||||
d = x.substr(i);
|
||||
p = {t:""};
|
||||
|
||||
|
@ -4804,6 +4812,12 @@ var RecordEnum = {
|
|||
};
|
||||
|
||||
var evert_RE = evert_key(RecordEnum, 'n');
|
||||
/* Helper function to call out to ODS parser */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./dist/od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
||||
function fix_opts_func(defaults) {
|
||||
return function fix_opts(opts) {
|
||||
for(var i = 0; i != defaults.length; ++i) {
|
||||
|
@ -4861,6 +4875,10 @@ function parse_zip(zip, opts) {
|
|||
opts = opts || {};
|
||||
fix_read_opts(opts);
|
||||
reset_cp();
|
||||
|
||||
/* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
|
||||
if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
|
||||
|
||||
var entries = keys(zip.files).filter(nodirs).sort();
|
||||
var dir = parse_ct(getzipdata(zip, '[Content_Types].xml'), opts);
|
||||
var xlsb = false;
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -32,7 +32,7 @@ Output Format:
|
|||
<input type="radio" name="format" value="json"> JSON<br>
|
||||
<input type="radio" name="format" value="form"> FORMULAE<br> -->
|
||||
|
||||
<div id="drop">Drop an XLSX or XLSM or XLSB file here to see sheet data</div>
|
||||
<div id="drop">Drop an XLSX / XLSM / XLSB / ODS file here to see sheet data</div>
|
||||
<p><input type="file" name="xlfile" id="xlf" /> ... or click here to select a file</p>
|
||||
<textarea id="b64data">... or paste a base64-encoding here</textarea>
|
||||
<input type="button" id="dotext" value="Click here to process the base64 text" onclick="b64it();"/><br />
|
||||
|
@ -47,6 +47,8 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
|
|||
<script src="shim.js"></script>
|
||||
<script src="jszip.js"></script>
|
||||
<script src="xlsx.js"></script>
|
||||
<!-- uncomment the next line here and in xlsxworker.js for ODS support -->
|
||||
<script src="dist/ods.js"></script>
|
||||
<script>
|
||||
var rABS = typeof FileReader !== "undefined" && typeof FileReader.prototype !== "undefined" && typeof FileReader.prototype.readAsBinaryString !== "undefined";
|
||||
if(!rABS) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"xlsx",
|
||||
"xlsm",
|
||||
"xlsb",
|
||||
"ods",
|
||||
"js-xlsx"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
/* ods.js (C) 2014 SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint -W041 */
|
||||
var ODS = {};
|
||||
(function make_ods(ODS) {
|
||||
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
|
||||
var get_utils = function() {
|
||||
if(typeof XLSX !== 'undefined') return XLSX.utils;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') return require('xl' + 'sx').utils;
|
||||
throw new Error("Cannot find XLSX utils");
|
||||
};
|
||||
var has_buf = (typeof Buffer !== 'undefined');
|
||||
function getdata(data) {
|
||||
if(!data) return null;
|
||||
if(data.data) return data.data;
|
||||
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
|
||||
if(data.asBinary) return data.asBinary();
|
||||
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
|
||||
return null;
|
||||
}
|
||||
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
if(!safe) return getdata(getzipfile(zip, file));
|
||||
if(!file) return null;
|
||||
try { return getzipdata(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
var _fs, jszip;
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
if(has_buf && typeof jszip === 'undefined') jszip = require('js'+'zip');
|
||||
if(typeof jszip === 'undefined') jszip = require('./js'+'zip').JSZip;
|
||||
_fs = require('f'+'s');
|
||||
}
|
||||
}
|
||||
var attregexg=/\b[\w:-]+=["'][^"]*['"]/g;
|
||||
var tagregex=/<[^>]*>/g;
|
||||
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
|
||||
function parsexmltag(tag, skip_root) {
|
||||
var z = [];
|
||||
var eq = 0, c = 0;
|
||||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
|
||||
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
|
||||
if(j===q.length) z[q] = v;
|
||||
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
|
||||
|
||||
var encodings = {
|
||||
'"': '"',
|
||||
''': "'",
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencoding = {
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencstr = "&<>'\"".split("");
|
||||
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]+)_/g;
|
||||
function unescapexml(text){
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
}
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text){
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value, tag) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function datenum(v) {
|
||||
var epoch = Date.parse(v);
|
||||
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
/* ISO 8601 Duration */
|
||||
function parse_isodur(s) {
|
||||
var sec = 0, mt = 0, time = false;
|
||||
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
|
||||
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
|
||||
for(var i = 1; i != m.length; ++i) {
|
||||
if(!m[i]) continue;
|
||||
mt = 1;
|
||||
if(i > 3) time = true;
|
||||
switch(m[i].substr(m[i].length-1)) {
|
||||
case 'Y':
|
||||
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
|
||||
case 'D': mt *= 24;
|
||||
/* falls through */
|
||||
case 'H': mt *= 60;
|
||||
/* falls through */
|
||||
case 'M':
|
||||
if(!time) throw new Error("Unsupported ISO Duration Field: M");
|
||||
else mt *= 60;
|
||||
/* falls through */
|
||||
case 'S': break;
|
||||
}
|
||||
sec += mt * parseInt(m[i], 10);
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
if(typeof d === 'string') return d;
|
||||
throw "badf";
|
||||
}
|
||||
|
||||
var xlmlregex = /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/mg;
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
var parse_manifest = function(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0]);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
case 'algorithm': // 4.5 <manifest:algorithm>
|
||||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: throw Rn;
|
||||
}
|
||||
};
|
||||
var parse_text_p = function(text, tag) {
|
||||
return text;
|
||||
};
|
||||
var parse_content_xml = (function() {
|
||||
|
||||
var number_formats = {
|
||||
/* ods name: [short ssf fmt, long ssf fmt] */
|
||||
day: ["d", "dd"],
|
||||
month: ["m", "mm"],
|
||||
year: ["y", "yy"],
|
||||
hours: ["h", "hh"],
|
||||
minutes: ["m", "mm"],
|
||||
seconds: ["s", "ss"],
|
||||
"am-pm": ["A/P", "AM/PM"],
|
||||
"day-of-week": ["ddd", "dddd"]
|
||||
};
|
||||
|
||||
return function pcx(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var state = [], tmp;
|
||||
var tag;
|
||||
var NFtag, NF, pidx;
|
||||
var sheetag;
|
||||
var Sheets = {}, SheetNames = [], ws = {};
|
||||
var Rn, q;
|
||||
var ctag;
|
||||
var textp, textpidx, textptag;
|
||||
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0]);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'table-row':
|
||||
if(Rn[1] === '/') break;
|
||||
++R; C = -1; break; // 9.1.3 <table:table-row>
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') { ++C; break; } /* stub */
|
||||
if(Rn[1]!=='/') {
|
||||
++C;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
q = {t:ctag['value-type'], v:null};
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'string': q.t = 'str'; break;
|
||||
default: throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 'str') q.v = textp;
|
||||
if(textp) q.w = textp;
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
q = null;
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
case 'document-content': // 3.1.3.2 <office:document-content>
|
||||
case 'spreadsheet': // 3.7 <office:spreadsheet>
|
||||
case 'scripts': // 3.12 <office:scripts>
|
||||
case 'font-face-decls': // 3.14 <office:font-face-decls>
|
||||
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
|
||||
break;
|
||||
|
||||
case 'number-style': // 16.27.2 <number:number-style>
|
||||
case 'percentage-style': // 16.27.9 <number:percentage-style>
|
||||
case 'date-style': // 16.27.10 <number:date-style>
|
||||
case 'time-style': // 16.27.18 <number:time-style>
|
||||
if(Rn[1]==='/'){
|
||||
number_format_map[NFtag.name] = NF;
|
||||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0]);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
case 'script': break; // 3.13 <office:script>
|
||||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
case 'table-properties': break; // 17.15 <style:table-properties>
|
||||
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
|
||||
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
|
||||
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
|
||||
|
||||
case 'number': // 16.27.3 <number:number>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
case 'era': // 16.27.14 <number:era>
|
||||
case 'day-of-week': // 16.27.15 <number:day-of-week>
|
||||
case 'week-of-year': // 16.27.16 <number:week-of-year>
|
||||
case 'quarter': // 16.27.17 <number:quarter>
|
||||
case 'hours': // 16.27.19 <number:hours>
|
||||
case 'minutes': // 16.27.20 <number:minutes>
|
||||
case 'seconds': // 16.27.21 <number:seconds>
|
||||
case 'am-pm': // 16.27.22 <number:am-pm>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
|
||||
case 'boolean': break; // 16.27.24 <number:boolean>
|
||||
case 'text-style': break; // 16.27.25 <number:text-style>
|
||||
case 'text': // 16.27.26 <number:text>
|
||||
if(Rn[0].substr(-2) === "/>") break;
|
||||
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
|
||||
case 'number-style':
|
||||
case 'date-style':
|
||||
case 'time-style':
|
||||
NF += str.slice(pidx, Rn.index);
|
||||
break;
|
||||
}
|
||||
else pidx = Rn.index + Rn[0].length;
|
||||
break;
|
||||
case 'text-content': break; // 16.27.27 <number:text-content>
|
||||
case 'text-properties': break; // 16.27.27 <style:text-properties>
|
||||
|
||||
case 'body': break; // 3.3 16.9.6 19.726.3
|
||||
|
||||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'graphic-properties': break;
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.11 <table:named-range>
|
||||
case 'span': break; // <text:span>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0]); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
case 'annotation': break;
|
||||
default: throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
SheetNames: SheetNames
|
||||
};
|
||||
return out;
|
||||
};
|
||||
})();
|
||||
/* Part 3: Packages */
|
||||
var parse_ods = function(zip, opts) {
|
||||
//var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'));
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'));
|
||||
};
|
||||
ODS.parse_ods = parse_ods;
|
||||
})(typeof exports !== 'undefined' ? exports : ODS);
|
|
@ -0,0 +1,6 @@
|
|||
/* ods.js (C) 2014 SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint -W041 */
|
||||
var ODS = {};
|
||||
(function make_ods(ODS) {
|
||||
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
|
|
@ -0,0 +1,5 @@
|
|||
var get_utils = function() {
|
||||
if(typeof XLSX !== 'undefined') return XLSX.utils;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') return require('xl' + 'sx').utils;
|
||||
throw new Error("Cannot find XLSX utils");
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
var has_buf = (typeof Buffer !== 'undefined');
|
|
@ -0,0 +1,37 @@
|
|||
function getdata(data) {
|
||||
if(!data) return null;
|
||||
if(data.data) return data.data;
|
||||
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
|
||||
if(data.asBinary) return data.asBinary();
|
||||
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
|
||||
return null;
|
||||
}
|
||||
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
if(!safe) return getdata(getzipfile(zip, file));
|
||||
if(!file) return null;
|
||||
try { return getzipdata(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
var _fs, jszip;
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
if(has_buf && typeof jszip === 'undefined') jszip = require('js'+'zip');
|
||||
if(typeof jszip === 'undefined') jszip = require('./js'+'zip').JSZip;
|
||||
_fs = require('f'+'s');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
var attregexg=/\b[\w:-]+=["'][^"]*['"]/g;
|
||||
var tagregex=/<[^>]*>/g;
|
||||
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
|
||||
function parsexmltag(tag, skip_root) {
|
||||
var z = [];
|
||||
var eq = 0, c = 0;
|
||||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
|
||||
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
|
||||
if(j===q.length) z[q] = v;
|
||||
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
|
||||
|
||||
var encodings = {
|
||||
'"': '"',
|
||||
''': "'",
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencoding = {
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencstr = "&<>'\"".split("");
|
||||
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]+)_/g;
|
||||
function unescapexml(text){
|
||||
var s = text + '';
|
||||
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
|
||||
}
|
||||
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
|
||||
function escapexml(text){
|
||||
var s = text + '';
|
||||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value, tag) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function datenum(v) {
|
||||
var epoch = Date.parse(v);
|
||||
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
/* ISO 8601 Duration */
|
||||
function parse_isodur(s) {
|
||||
var sec = 0, mt = 0, time = false;
|
||||
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
|
||||
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
|
||||
for(var i = 1; i != m.length; ++i) {
|
||||
if(!m[i]) continue;
|
||||
mt = 1;
|
||||
if(i > 3) time = true;
|
||||
switch(m[i].substr(m[i].length-1)) {
|
||||
case 'Y':
|
||||
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
|
||||
case 'D': mt *= 24;
|
||||
/* falls through */
|
||||
case 'H': mt *= 60;
|
||||
/* falls through */
|
||||
case 'M':
|
||||
if(!time) throw new Error("Unsupported ISO Duration Field: M");
|
||||
else mt *= 60;
|
||||
/* falls through */
|
||||
case 'S': break;
|
||||
}
|
||||
sec += mt * parseInt(m[i], 10);
|
||||
}
|
||||
return sec;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
if(typeof d === 'string') return d;
|
||||
throw "badf";
|
||||
}
|
||||
|
||||
var xlmlregex = /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/mg;
|
|
@ -0,0 +1,20 @@
|
|||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
var parse_manifest = function(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0]);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
case 'algorithm': // 4.5 <manifest:algorithm>
|
||||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: throw Rn;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
var parse_text_p = function(text, tag) {
|
||||
return text;
|
||||
};
|
|
@ -0,0 +1,176 @@
|
|||
var parse_content_xml = (function() {
|
||||
|
||||
var number_formats = {
|
||||
/* ods name: [short ssf fmt, long ssf fmt] */
|
||||
day: ["d", "dd"],
|
||||
month: ["m", "mm"],
|
||||
year: ["y", "yy"],
|
||||
hours: ["h", "hh"],
|
||||
minutes: ["m", "mm"],
|
||||
seconds: ["s", "ss"],
|
||||
"am-pm": ["A/P", "AM/PM"],
|
||||
"day-of-week": ["ddd", "dddd"]
|
||||
};
|
||||
|
||||
return function pcx(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var state = [], tmp;
|
||||
var tag;
|
||||
var NFtag, NF, pidx;
|
||||
var sheetag;
|
||||
var Sheets = {}, SheetNames = [], ws = {};
|
||||
var Rn, q;
|
||||
var ctag;
|
||||
var textp, textpidx, textptag;
|
||||
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0]);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'table-row':
|
||||
if(Rn[1] === '/') break;
|
||||
++R; C = -1; break; // 9.1.3 <table:table-row>
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') { ++C; break; } /* stub */
|
||||
if(Rn[1]!=='/') {
|
||||
++C;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
q = {t:ctag['value-type'], v:null};
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'string': q.t = 'str'; break;
|
||||
default: throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 'str') q.v = textp;
|
||||
if(textp) q.w = textp;
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
q = null;
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
case 'document-content': // 3.1.3.2 <office:document-content>
|
||||
case 'spreadsheet': // 3.7 <office:spreadsheet>
|
||||
case 'scripts': // 3.12 <office:scripts>
|
||||
case 'font-face-decls': // 3.14 <office:font-face-decls>
|
||||
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
|
||||
break;
|
||||
|
||||
case 'number-style': // 16.27.2 <number:number-style>
|
||||
case 'percentage-style': // 16.27.9 <number:percentage-style>
|
||||
case 'date-style': // 16.27.10 <number:date-style>
|
||||
case 'time-style': // 16.27.18 <number:time-style>
|
||||
if(Rn[1]==='/'){
|
||||
number_format_map[NFtag.name] = NF;
|
||||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0]);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
case 'script': break; // 3.13 <office:script>
|
||||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
case 'table-properties': break; // 17.15 <style:table-properties>
|
||||
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
|
||||
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
|
||||
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
|
||||
|
||||
case 'number': // 16.27.3 <number:number>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
case 'era': // 16.27.14 <number:era>
|
||||
case 'day-of-week': // 16.27.15 <number:day-of-week>
|
||||
case 'week-of-year': // 16.27.16 <number:week-of-year>
|
||||
case 'quarter': // 16.27.17 <number:quarter>
|
||||
case 'hours': // 16.27.19 <number:hours>
|
||||
case 'minutes': // 16.27.20 <number:minutes>
|
||||
case 'seconds': // 16.27.21 <number:seconds>
|
||||
case 'am-pm': // 16.27.22 <number:am-pm>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
|
||||
case 'boolean': break; // 16.27.24 <number:boolean>
|
||||
case 'text-style': break; // 16.27.25 <number:text-style>
|
||||
case 'text': // 16.27.26 <number:text>
|
||||
if(Rn[0].substr(-2) === "/>") break;
|
||||
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
|
||||
case 'number-style':
|
||||
case 'date-style':
|
||||
case 'time-style':
|
||||
NF += str.slice(pidx, Rn.index);
|
||||
break;
|
||||
}
|
||||
else pidx = Rn.index + Rn[0].length;
|
||||
break;
|
||||
case 'text-content': break; // 16.27.27 <number:text-content>
|
||||
case 'text-properties': break; // 16.27.27 <style:text-properties>
|
||||
|
||||
case 'body': break; // 3.3 16.9.6 19.726.3
|
||||
|
||||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'graphic-properties': break;
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.11 <table:named-range>
|
||||
case 'span': break; // <text:span>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0]); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
case 'annotation': break;
|
||||
default: throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
SheetNames: SheetNames
|
||||
};
|
||||
return out;
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,5 @@
|
|||
/* Part 3: Packages */
|
||||
var parse_ods = function(zip, opts) {
|
||||
//var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'));
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'));
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
ODS.parse_ods = parse_ods;
|
|
@ -0,0 +1 @@
|
|||
})(typeof exports !== 'undefined' ? exports : ODS);
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.7.10",
|
||||
"version": "0.7.11",
|
||||
"author": "sheetjs",
|
||||
"description": "Excel 2007+ spreadsheet (XLSB/XLSX/XLSM) parser and writer",
|
||||
"keywords": [ "excel", "xlsx", "xlsb", "xlsm", "office", "spreadsheet" ],
|
||||
"description": "Excel 2007+ spreadsheet (XLSB/XLSX/XLSM) and ODS parser and writer",
|
||||
"keywords": [ "excel", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
|
||||
"bin": {
|
||||
"xlsx": "./bin/xlsx.njs"
|
||||
},
|
||||
|
|
8
test.js
8
test.js
|
@ -15,8 +15,7 @@ var ex = fullex;
|
|||
if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
|
||||
if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
|
||||
var exp = ex.map(function(x){ return x + ".pending"; });
|
||||
var ow = 5;
|
||||
function test_file(x){return ex.indexOf(x.substr(-ow))>=0||exp.indexOf(x.substr(-8-ow))>=0;}
|
||||
function test_file(x){ return ex.indexOf(x.substr(-5))>=0||exp.indexOf(x.substr(-13))>=0 || ex.indexOf(x.substr(-4))>=0||exp.indexOf(x.substr(-12))>=0; }
|
||||
|
||||
var files = (fs.existsSync('tests.lst') ? fs.readFileSync('tests.lst', 'utf-8').split("\n") : fs.readdirSync('test_files')).filter(test_file);
|
||||
var fileA = (fs.existsSync('testA.lst') ? fs.readFileSync('testA.lst', 'utf-8').split("\n") : []).filter(test_file);
|
||||
|
@ -92,8 +91,8 @@ function parsetest(x, wb, full, ext) {
|
|||
if(!full) return;
|
||||
var getfile = function(dir, x, i, type) {
|
||||
var name = (dir + x + '.' + i + type);
|
||||
if(x.substr(-ow) === ".xlsb") {
|
||||
root = x.slice(0,-ow);
|
||||
if(x.substr(-5) === ".xlsb") {
|
||||
root = x.slice(0,-5);
|
||||
if(!fs.existsSync(name)) name=(dir + root + '.xlsx.' + i + type);
|
||||
if(!fs.existsSync(name)) name=(dir + root + '.xlsm.' + i + type);
|
||||
if(!fs.existsSync(name)) name=(dir + root + '.xls.' + i + type);
|
||||
|
@ -689,7 +688,6 @@ describe('invalid files', function() {
|
|||
describe('parse', function() { [
|
||||
['passwords', 'excel-reader-xlsx_error03.xlsx'],
|
||||
['XLS files', 'roo_type_excel.xlsx'],
|
||||
['ODS files', 'roo_type_openoffice.xlsx'],
|
||||
['DOC files', 'word_doc.doc']
|
||||
].forEach(function(w) { it('should fail on ' + w[0], function() {
|
||||
assert.throws(function() { X.readFile(dir + w[1]); });
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5308987eaeb01103964363cdc745b8340795d63c
|
||||
Subproject commit 7940cf6da4eb8a4775f5d28a61799772a1e26e6a
|
24
tests.lst
24
tests.lst
|
@ -329,3 +329,27 @@ number_format_russian.xlsm
|
|||
numfmt_1_russian.xlsm
|
||||
openpyxl_r_vba-test.xlsm
|
||||
pivot_table_test.xlsm
|
||||
roo_Bibelbund.ods
|
||||
roo_Bibelbund1.ods
|
||||
roo_bbu.ods
|
||||
roo_boolean.ods
|
||||
roo_borders.ods
|
||||
roo_comments.ods
|
||||
roo_datetime.ods
|
||||
roo_dreimalvier.ods
|
||||
roo_emptysheets.ods
|
||||
roo_formula.ods
|
||||
roo_html-escape.ods
|
||||
roo_matrix.ods
|
||||
roo_named_cells.ods
|
||||
roo_numbers1.ods
|
||||
roo_only_one_sheet.ods
|
||||
roo_paragraph.ods
|
||||
roo_ric.ods
|
||||
roo_simple_spreadsheet.ods
|
||||
roo_simple_spreadsheet_from_italo.ods
|
||||
roo_style.ods
|
||||
roo_time-test.ods
|
||||
roo_type_excel.ods.pending
|
||||
roo_type_excelx.ods
|
||||
roo_whitespace.ods
|
||||
|
|
38
xlsx.js
38
xlsx.js
|
@ -3,7 +3,7 @@
|
|||
/*jshint -W041 */
|
||||
var XLSX = {};
|
||||
(function(XLSX){
|
||||
XLSX.version = '0.7.10';
|
||||
XLSX.version = '0.7.11';
|
||||
var current_codepage = 1252, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
|
@ -847,11 +847,17 @@ function getdata(data) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
throw new Error("Cannot find file " + file + " in zip");
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
|
@ -2934,13 +2940,13 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
|
|||
}
|
||||
|
||||
var parse_ws_xml_data = (function parse_ws_xml_data_factory() {
|
||||
var cellregex = /<(?:\w+:)?c /, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var rregex = /r=["']([^"']*)["']/, isregex = /<is>([\S\s]*?)<\/is>/;
|
||||
var match_v = matchtag("v"), match_f = matchtag("f");
|
||||
|
||||
return function parse_ws_xml_data(sdata, s, opts, guess) {
|
||||
var ri = 0, x = "", cells = [], cref = [], idx = 0, i=0, cc=0, d="", p;
|
||||
var tag;
|
||||
var tag, tagr = 0, tagc = 0;
|
||||
var sstr;
|
||||
var fmtid = 0, fillid = 0, do_format = Array.isArray(styles.CellXf), cf;
|
||||
for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
|
||||
|
@ -2951,18 +2957,19 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
|
|||
/* 18.3.1.73 row CT_Row */
|
||||
for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
|
||||
tag = parsexmltag(x.substr(0,ri), true);
|
||||
var tagr = parseInt(tag.r, 10);
|
||||
/* SpreadSheetGear uses implicit r/c */
|
||||
tagr = typeof tag.r !== 'undefined' ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
|
||||
if(opts.sheetRows && opts.sheetRows < tagr) continue;
|
||||
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
|
||||
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
|
||||
|
||||
/* 18.3.1.4 c CT_Cell */
|
||||
cells = x.substr(ri).split(cellregex);
|
||||
for(ri = 1; ri != cells.length; ++ri) {
|
||||
for(ri = typeof tag.r === 'undefined' ? 0 : 1; ri != cells.length; ++ri) {
|
||||
x = cells[ri].trim();
|
||||
if(x.length === 0) continue;
|
||||
cref = x.match(rregex); idx = ri; i=0; cc=0;
|
||||
x = "<c " + x;
|
||||
x = "<c " + (x.substr(0,1)=="<"?">":"") + x;
|
||||
if(cref !== null && cref.length === 2) {
|
||||
idx = 0; d=cref[1];
|
||||
for(i=0; i != d.length; ++i) {
|
||||
|
@ -2970,10 +2977,11 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
|
|||
idx = 26*idx + cc;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
|
||||
tagc = idx;
|
||||
} else ++tagc;
|
||||
for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
|
||||
tag = parsexmltag(x.substr(0,i), true);
|
||||
if(!tag.r) tag.r = utils.encode_cell({r:tagr-1, c:tagc});
|
||||
d = x.substr(i);
|
||||
p = {t:""};
|
||||
|
||||
|
@ -4804,6 +4812,12 @@ var RecordEnum = {
|
|||
};
|
||||
|
||||
var evert_RE = evert_key(RecordEnum, 'n');
|
||||
/* Helper function to call out to ODS parser */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./dist/od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
||||
function fix_opts_func(defaults) {
|
||||
return function fix_opts(opts) {
|
||||
for(var i = 0; i != defaults.length; ++i) {
|
||||
|
@ -4861,6 +4875,10 @@ function parse_zip(zip, opts) {
|
|||
opts = opts || {};
|
||||
fix_read_opts(opts);
|
||||
reset_cp();
|
||||
|
||||
/* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
|
||||
if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
|
||||
|
||||
var entries = keys(zip.files).filter(nodirs).sort();
|
||||
var dir = parse_ct(getzipdata(zip, '[Content_Types].xml'), opts);
|
||||
var xlsb = false;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
//importScripts('dist/cpexcel.js');
|
||||
importScripts('jszip.js');
|
||||
importScripts('xlsx.js');
|
||||
/* uncomment the next line for ODS support */
|
||||
importScripts('dist/ods.js');
|
||||
postMessage({t:"ready"});
|
||||
|
||||
onmessage = function (oEvent) {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
//importScripts('dist/cpexcel.js');
|
||||
importScripts('jszip.js');
|
||||
importScripts('xlsx.js');
|
||||
/* uncomment the next line for ODS support */
|
||||
importScripts('dist/ods.js');
|
||||
postMessage({t:"ready"});
|
||||
|
||||
function ab2str(data) {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
//importScripts('dist/cpexcel.js');
|
||||
importScripts('jszip.js');
|
||||
importScripts('xlsx.js');
|
||||
/* uncomment the next line for ODS support */
|
||||
importScripts('dist/ods.js');
|
||||
postMessage({t:"ready"});
|
||||
|
||||
function ab2str(data) {
|
||||
|
|
Loading…
Reference in New Issue