version bump 0.7.12: cell type 'd'

- more structure in the theme parsing
- cellDates option on parsing side creates date cells
- cellDates option on writing side creates cells with type 'd'
- cell types clarified, type 'str' phased out
- README clarifications
- more tests to ensure date consistency
- more test cases for ODS
This commit is contained in:
SheetJS 2014-10-26 01:26:18 -04:00
parent 61d2e55cc6
commit f9097d403b
31 changed files with 658 additions and 163 deletions

@ -13,7 +13,7 @@ tmp
.jshintrc
CONTRIBUTING.md
Makefile
tests.lst
*.lst
.npmignore
xlsworker.js
shim.js
@ -23,3 +23,4 @@ test.js
.travis.yml
bits/
odsbits/
tests/

@ -1,7 +1,12 @@
# xlsx
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.
Parser and writer for Excel 2007+ (XLSX/XLSM/XLSB) files and parser for ODS.
Pure-JS cleanroom implementation from the Office Open XML spec, [MS-XLSB], ODF
specifications and related documents.
Demo: <http://oss.sheetjs.com/js-xlsx>
Source: <http://git.io/xlsx>
## Installation
@ -11,7 +16,6 @@ In [nodejs](https://www.npmjs.org/package/xlsx):
In the browser:
<!-- This is the only file you need (includes xlsx.js and jszip) -->
<script lang="javascript" src="dist/xlsx.core.min.js"></script>
In [bower](http://bower.io/search/?q=js-xlsx):
@ -21,12 +25,6 @@ In [bower](http://bower.io/search/?q=js-xlsx):
CDNjs automatically pulls the latest version and makes all versions available at
<http://cdnjs.com/libraries/xlsx>
Older versions of this README recommended a more explicit approach:
<!-- JSZip must be included before xlsx.js -->
<script lang="javascript" src="/path/to/jszip.js"></script>
<script lang="javascript" src="/path/to/xlsx.js"></script>
## Optional Modules
The nodejs version automatically requires modules for additional features. Some
@ -43,7 +41,7 @@ An appropriate version for each dependency is included in the dist/ directory.
The complete single-file version is generated at `dist/xlsx.full.min.js`
## ECMAScript 5 compatibility
## ECMAScript 5 Compatibility
Since xlsx.js uses ES5 functions like `Array#forEach`, older browsers require
[Polyfills](http://git.io/QVh77g). This repo and the gh-pages branch include
@ -55,9 +53,10 @@ To use the shim, add the shim before the script tag that loads xlsx.js:
## Parsing Workbooks
For parsing, the first step is to read the file.
For parsing, the first step is to read the file. This involves acquiring the
data and feeding it into the library. Here are a few common scenarios:
- nodejs:
- nodejs readFile:
```
if(typeof require !== 'undefined') XLSX = require('xlsx');
@ -65,8 +64,8 @@ var workbook = XLSX.readFile('test.xlsx');
/* DO SOMETHING WITH workbook HERE */
```
- ajax (for a more complete example that works in older versions of IE, check the
demo at <http://oss.sheetjs.com/js-xlsx/ajax.html>):
- ajax (for a more complete example that works in older browsers, check the demo
at <http://oss.sheetjs.com/js-xlsx/ajax.html>):
```
/* set up XMLHttpRequest */
@ -141,6 +140,8 @@ function handleFile(e) {
input_dom_element.addEventListener('change', handleFile, false);
```
## Working with the Workbook
This example walks through every cell of every sheet and dumps the values:
```
@ -179,16 +180,20 @@ Some helper functions in `XLSX.utils` generate different views of the sheets:
## Writing Workbooks
Assuming `workbook` is a workbook object, just call write:
For writing, the first step is to generate output data. The helper functions
`write` and `writeFile` will produce the data in various formats suitable for
dissemination. The second step is to actual share the data with the end point.
Assuming `workbook` is a workbook object:
- nodejs write to file:
```
/* output format determined by filename */
XLSX.writeFile(workbook, 'out.xlsx');
/* at this point, out.xlsx is a file that you can distribute */
```
- write to binary string (using FileSaver.js)
- write to binary string (using FileSaver.js):
```
/* bookType can be 'xlsx' or 'xlsm' or 'xlsb' */
@ -203,6 +208,7 @@ function s2ab(s) {
return buf;
}
/* the saveAs call downloads a file on the local machine */
saveAs(new Blob([s2ab(wbout)],{type:""}), "test.xlsx")
```
@ -276,9 +282,9 @@ for(var R = range.s.r; R <= range.e.r; ++R) {
| Key | Description |
| --- | ----------- |
| `v` | raw value ** |
| `v` | raw value (see Data Types section for more info) |
| `w` | formatted text (if applicable) |
| `t` | cell type: `b` Boolean, `n` Number, `e` error, `s/str` String |
| `t` | cell type: `b` Boolean, `n` Number, `e` error, `s` String, `d` Date |
| `f` | cell formula (if applicable) |
| `r` | rich text encoding (if applicable) |
| `h` | HTML rendering of the rich text (if applicable) |
@ -287,13 +293,46 @@ for(var R = range.s.r; R <= range.e.r; ++R) {
| `l` | cell hyperlink object (.Target holds link, .tooltip is tooltip) |
| `s` | the style/theme of the cell (if applicable) |
- For dates, `.v` holds the raw date code from the sheet and `.w` holds the text
Built-in export utilities (such as the CSV exporter) will use the `w` text if it
is available. To change a value, be sure to delete `cell.w` (or set it to
`undefined`) before attempting to export. The utilities will regenerate the `w`
text from the number format (`cell.z`) and the raw value if possible.
### Data Types
The raw value is stored in the `v` field, interpreted based on the `t` field.
Type `b` is the Boolean type. `v` is interpreted according to JS truth tables
Type `e` is the Error type. `v` holds the number and `w` holds the common name:
| Value | Error Meaning |
| ----: | :------------ |
| 0x00 | #NULL! |
| 0x07 | #DIV/0! |
| 0x0F | #VALUE! |
| 0x17 | #REF! |
| 0x1D | #NAME? |
| 0x24 | #NUM! |
| 0x2A | #N/A |
| 0x2B | #GETTING_DATA |
Type `n` is the Number type. This includes all forms of data that Excel stores
as numbers, such as dates/times and Boolean fields. Excel exclusively uses data
that can be fit in an IEEE754 floating point number, just like JS Number, so the
`v` field holds the raw number. The `w` field holds formatted text.
Type `d` is the Date type, generated only when the option `cellDates` is passed.
Since JSON does not have a natural Date type, parsers are generally expected to
store ISO 8601 Date strings like you would get from `date.toISOString()`. On
the other hand, writers and exporters should be able to handle date strings and
JS Date objects. Note that Excel disregards the timezone modifier and treats all
dates in the local timezone. js-xlsx does not correct for this error.
Type `s` is the String type. `v` should be explicitly stored as a string to
avoid possible confusion.
### Worksheet Object
Each key that does not start with `!` maps to a cell (using `A-1` notation)
@ -348,6 +387,7 @@ The exported `read` and `readFile` functions accept an options argument:
| cellHTML | true | Parse rich text and save HTML to the .h field |
| cellNF | false | Save number format string to the .z field |
| cellStyles | false | Save style/theme info to the .s field |
| cellDates | false | Store dates as type `d` (default is `n`) ** |
| sheetStubs | false | Create cell objects for stub cells |
| sheetRows | 0 | If >0, read the first `sheetRows` rows ** |
| bookDeps | false | If true, parse calculation chains |
@ -356,7 +396,7 @@ The exported `read` and `readFile` functions accept an options argument:
| bookSheets | false | If true, only parse enough to get the sheet names |
| bookVBA | false | If true, expose vbaProject.bin to `vbaraw` field ** |
- Even if `cellNF` is false, formatted text (.w) will be generated
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
- In some cases, sheets may be parsed even if `bookSheets` is false.
- `bookSheets` and `bookProps` combine to give both sets of information
- `Deps` will be an empty object if `bookDeps` is falsy
@ -365,6 +405,7 @@ The exported `read` and `readFile` functions accept an options argument:
- `sheetRows-1` rows will be generated when looking at the JSON object output
(since the header row is counted as a row when parsing the data)
- `bookVBA` merely exposes the raw vba object. It does not parse the data.
- `cellDates` currently does not convert numerical dates to JS dates.
The defaults are enumerated in bits/84_defaults.js
@ -374,6 +415,7 @@ The exported `write` and `writeFile` functions accept an options argument:
| Option Name | Default | Description |
| :---------- | ------: | :---------- |
| cellDates | false | Store dates as type `d` (default is `n`) |
| bookSST | false | Generate Shared String Table ** |
| bookType | 'xlsx' | Type of Workbook ("xlsx" or "xlsm" or "xlsb") |
@ -382,6 +424,9 @@ The exported `write` and `writeFile` functions accept an options argument:
- `bookType = 'xlsb'` is stubbed and far from complete
- The raw data is the only thing guaranteed to be saved. Formulae, formatting,
and other niceties may not be serialized (pending CSF standardization)
- `cellDates` only applies to XLSX output and is not guaranteed to work with
third-party readers. Excel itself does not usually write cells with type `d`
so non-Excel tools may ignore the data or blow up in the presence of dates.
## Tested Environments
@ -433,6 +478,9 @@ $ make
$ diff xlsx.js xlsx.new.js
```
To produce the dist files, run `make dist`. The dist files are updated in each
version release and should not be committed between versions.
## XLS Support
XLS is available in [js-xls](http://git.io/xls).

@ -1 +1 @@
XLSX.version = '0.7.11';
XLSX.version = '0.7.12';

@ -36,7 +36,7 @@ function parse_fills(t, opts) {
/* Excel uses ARGB strings */
if(y.rgb) fill.fgColor.rgb = y.rgb.substring(y.rgb.length - 6);
break;
case '<bgColor/>': case '</fgColor>': break;
case '<fgColor/>': case '</fgColor>': break;
default: if(opts.WTF) throw 'unrecognized ' + y[0] + ' in fills';
}
@ -125,7 +125,7 @@ return function parse_sty_xml(data, opts) {
if((t=data.match(numFmtRegex))) parse_numFmts(t, opts);
/* fonts CT_Fonts ? */
// if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);
/*if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);*/
/* fills CT_Fills */
if((t=data.match(fillsRegex))) parse_fills(t, opts);

@ -64,16 +64,47 @@ function parse_clrScheme(t, opts) {
});
}
var clrsregex = /<a:clrScheme([^>]*)>.*<\/a:clrScheme>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data, opts) {
if(!data || data.length === 0) return themes;
/* 20.1.4.1.18 fontScheme CT_FontScheme */
function parse_fontScheme(t, opts) { }
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
function parse_fmtScheme(t, opts) { }
var clrsregex = /<a:clrScheme([^>]*)>[^\u2603]*<\/a:clrScheme>/;
var fntsregex = /<a:fontScheme([^>]*)>[^\u2603]*<\/a:fontScheme>/;
var fmtsregex = /<a:fmtScheme([^>]*)>[^\u2603]*<\/a:fmtScheme>/;
/* 20.1.6.10 themeElements CT_BaseStyles */
function parse_themeElements(data, opts) {
themes.themeElements = {};
var t;
/* clrScheme CT_ColorScheme */
if((t=data.match(clrsregex))) parse_clrScheme(t, opts);
[
/* clrScheme CT_ColorScheme */
['clrScheme', clrsregex, parse_clrScheme],
/* fontScheme CT_FontScheme */
['fontScheme', fntsregex, parse_fontScheme],
/* fmtScheme CT_StyleMatrix */
['fmtScheme', fmtsregex, parse_fmtScheme]
].forEach(function(m) {
if(!(t=data.match(m[1]))) throw m[0] + ' not found in themeElements';
m[2](t, opts);
});
}
var themeltregex = /<a:themeElements([^>]*)>[^\u2603]*<\/a:themeElements>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data, opts) {
/* 20.1.6.9 theme CT_OfficeStyleSheet */
if(!data || data.length === 0) return themes;
var t;
/* themeElements CT_BaseStyles */
if(!(t=data.match(themeltregex))) throw 'themeElements not found in theme';
parse_themeElements(t[0], opts);
return themes;
}

@ -24,14 +24,21 @@ function get_cell_style(styles, cell, opts) {
function safe_format(p, fmtid, fillid, opts) {
try {
if(fmtid === 0) {
if(p.t === 'e') p.w = p.w || BErr[p.v];
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v,_ssfopts);
else p.w = SSF._general_num(p.v,_ssfopts);
}
else if(p.t === 'd') {
var dd = datenum(p.v);
if((dd|0) === dd) p.w = SSF._general_int(dd,_ssfopts);
else p.w = SSF._general_num(dd,_ssfopts);
}
else if(p.v === undefined) return "";
else p.w = SSF._general(p.v,_ssfopts);
}
else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
else p.w = SSF.format(fmtid,p.v,_ssfopts);
if(opts.cellNF) p.z = SSF._table[fmtid];
} catch(e) { if(opts.WTF) throw e; }

@ -83,7 +83,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:"str",v:undefined};
if(!s[addr]) s[addr] = {t:"stub",v:undefined};
s[addr].l = val;
}
}
@ -124,9 +124,19 @@ function write_ws_xml_cols(ws, cols) {
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(cell.v === undefined) return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
switch(cell.t) {
case 'b': vv = cell.v ? "1" : "0"; break;
case 'n': case 'e': vv = ''+cell.v; break;
case 'n': vv = ''+cell.v; break;
case 'e': vv = BErr[cell.v]; break;
case 'd':
if(opts.cellDates) vv = new Date(cell.v).toISOString();
else {
cell.t = 'n';
vv = ''+(cell.v = datenum(cell.v));
if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
}
break;
default: vv = cell.v; break;
}
var v = writetag('v', escapexml(vv)), o = {r:ref};
@ -135,6 +145,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(os !== 0) o.s = os;
switch(cell.t) {
case 'n': break;
case 'd': o.t = "d"; break;
case 'b': o.t = "b"; break;
case 'e': o.t = "e"; break;
default:
@ -144,6 +155,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
}
o.t = "str"; break;
}
if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
return writextag('c', v, o);
}
@ -199,7 +211,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 = "str";
p.t = "stub";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -213,19 +225,22 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;
break;
case 'str': if(p.v != null) p.v = utf8read(p.v); else p.v = ""; break;
case 'str':
p.t = "s";
p.v = (p.v!=null) ? utf8read(p.v) : '';
if(opts.cellHTML) p.h = p.v;
break;
case 'inlineStr':
cref = d.match(isregex);
p.t = 'str';
p.t = 's';
if(cref !== null) { sstr = parse_si(cref[1]); p.v = sstr.t; } else p.v = "";
break; // inline string
case 'b': p.v = parsexmlbool(p.v); break;
case 'd':
p.v = datenum(p.v);
p.t = 'n';
if(!opts.cellDates) { p.v = datenum(p.v); p.t = 'n'; }
break;
/* in case of error, stick value in .raw */
case 'e': p.raw = RBErr[p.v]; break;
/* error string in .v, number in .v */
case 'e': p.w = p.v; p.v = RBErr[p.v]; break;
}
/* formatting */
fmtid = fillid = 0;

@ -177,8 +177,8 @@ function parse_ws_bin(data, opts, rels) {
case 'n': p.v = val[1]; break;
case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
case 'b': p.v = val[1] ? true : false; break;
case 'e': p.raw = val[1]; p.v = BErr[p.raw]; break;
case 'str': p.v = utf8read(val[1]); break;
case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if(opts.cellFormula && val.length > 3) p.f = val[3];
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
@ -190,7 +190,7 @@ function parse_ws_bin(data, opts, rels) {
break;
case 'BrtCellBlank': if(!opts.sheetStubs) break;
p = {t:'str',v:undefined};
p = {t:'s',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;
@ -212,7 +212,7 @@ function parse_ws_bin(data, opts, rels) {
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:"str",v:undefined};
if(!s[addr]) s[addr] = {t:'s',v:undefined};
s[addr].l = val;
}
break;

@ -1,6 +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 module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
return ODS.parse_ods(zip, opts);
}

@ -13,6 +13,7 @@ var fix_read_opts = fix_opts_func([
['cellHTML', true], /* emit html string as .h */
['cellFormula', true], /* emit formulae as .f */
['cellStyles', false], /* emits style/theme as .s */
['cellDates', false], /* emit date cells with type `d` */
['sheetStubs', false], /* emit empty cells */
['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
@ -28,6 +29,8 @@ var fix_read_opts = fix_opts_func([
var fix_write_opts = fix_opts_func([
['cellDates', false], /* write date cells with type `d` */
['bookSST', false], /* Generate Shared String Table */
['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */

@ -107,7 +107,7 @@ function sheet_to_json(sheet, opts){
v = val.v;
switch(val.t){
case 'e': continue;
case 's': case 'str': break;
case 's': break;
case 'b': case 'n': break;
default: throw 'unrecognized type ' + val.t;
}

@ -2,7 +2,7 @@
"name": "js-xlsx",
"homepage": "https://github.com/SheetJS/js-xlsx",
"main": "dist/xlsx.js",
"version": "0.7.11",
"version": "0.7.12",
"ignore": [
"bin",
"bits",

2
dist/cpexcel.js vendored

@ -1,6 +1,6 @@
/* cpexcel.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/*jshint -W100 */
var cptable = {version:"1.3.4"};
var cptable = {version:"1.3.6"};
cptable[874] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~<7F><E282AC><EFBFBD><EFBFBD><EFBFBD><E280A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>“”•<E28093><E28094><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู<E0B8B9><E0B8BA><EFBFBD><EFBFBD>฿เแโใไๅๆ็่้๊๋์ํ๎๏๑๒๓๔๕๖๗๘๙๚๛<E0B99A><E0B99B><EFBFBD><EFBFBD>", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d[i]] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })();
cptable[932] = (function(){ var d = [], e = {}, D = [], j;
D[0] = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~<><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚<EFBE9E><EFBE9F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>".split("");

80
dist/ods.js vendored

@ -6,7 +6,12 @@ var 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;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../' + 'xlsx').utils;
} catch(e) {
try { return require('./' + 'xlsx').utils; }
catch(ee) { return require('xl' + 'sx').utils; }
}
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
@ -165,7 +170,24 @@ var parse_manifest = function(d, opts) {
}
};
var parse_text_p = function(text, tag) {
return text;
return utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig) {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};
var parse_content_xml = (function() {
@ -193,12 +215,14 @@ var parse_content_xml = (function() {
var textp, textpidx, textptag;
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
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);
if(merges.length) ws['!merges'] = merges;
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
@ -206,16 +230,22 @@ var parse_content_xml = (function() {
sheetag = parsexmltag(Rn[0]);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {};
ws = {}; merges = [];
}
break;
case 'table-row':
case 'table-row': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
++R; C = -1; break; // 9.1.3 <table:table-row>
++R; C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell':
if(Rn[0].charAt(Rn[0].length-2) === '/') { ++C; break; } /* stub */
if(Rn[1]!=='/') {
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0]);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
@ -223,24 +253,32 @@ var parse_content_xml = (function() {
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0]);
q = {t:ctag['value-type'], v:null};
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 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 'currency': 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;
case 'string': q.t = 's'; break;
default: throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 'str') q.v = textp;
if(q.t === 's') q.v = textp;
if(textp) q.w = textp;
ws[get_utils().encode_cell({r:R,c:C})] = q;
if(!(opts.sheetRows && opts.sheetRows < R)) ws[get_utils().encode_cell({r:R,c:C})] = q;
q = null;
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document-content': // 3.1.3.2 <office:document-content>
case 'spreadsheet': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
@ -249,6 +287,13 @@ var parse_content_xml = (function() {
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
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], false]);
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>
@ -334,7 +379,18 @@ var parse_content_xml = (function() {
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'annotation': break;
default: throw Rn;
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': break; // <*:title>
case 'desc': break; // <*:desc>
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
default: if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
@ -346,7 +402,7 @@ var parse_content_xml = (function() {
/* 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'));
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
};
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

10
dist/xlsx.full.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

104
dist/xlsx.js vendored

@ -3,7 +3,7 @@
/*jshint -W041 */
var XLSX = {};
(function(XLSX){
XLSX.version = '0.7.11';
XLSX.version = '0.7.12';
var current_codepage = 1252, current_cptable;
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
@ -2228,7 +2228,7 @@ function parse_fills(t, opts) {
/* Excel uses ARGB strings */
if(y.rgb) fill.fgColor.rgb = y.rgb.substring(y.rgb.length - 6);
break;
case '<bgColor/>': case '</fgColor>': break;
case '<fgColor/>': case '</fgColor>': break;
default: if(opts.WTF) throw 'unrecognized ' + y[0] + ' in fills';
}
@ -2317,7 +2317,7 @@ return function parse_sty_xml(data, opts) {
if((t=data.match(numFmtRegex))) parse_numFmts(t, opts);
/* fonts CT_Fonts ? */
// if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);
/*if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);*/
/* fills CT_Fills */
if((t=data.match(fillsRegex))) parse_fills(t, opts);
@ -2558,16 +2558,47 @@ function parse_clrScheme(t, opts) {
});
}
var clrsregex = /<a:clrScheme([^>]*)>.*<\/a:clrScheme>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data, opts) {
if(!data || data.length === 0) return themes;
/* 20.1.4.1.18 fontScheme CT_FontScheme */
function parse_fontScheme(t, opts) { }
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
function parse_fmtScheme(t, opts) { }
var clrsregex = /<a:clrScheme([^>]*)>[^\u2603]*<\/a:clrScheme>/;
var fntsregex = /<a:fontScheme([^>]*)>[^\u2603]*<\/a:fontScheme>/;
var fmtsregex = /<a:fmtScheme([^>]*)>[^\u2603]*<\/a:fmtScheme>/;
/* 20.1.6.10 themeElements CT_BaseStyles */
function parse_themeElements(data, opts) {
themes.themeElements = {};
var t;
/* clrScheme CT_ColorScheme */
if((t=data.match(clrsregex))) parse_clrScheme(t, opts);
[
/* clrScheme CT_ColorScheme */
['clrScheme', clrsregex, parse_clrScheme],
/* fontScheme CT_FontScheme */
['fontScheme', fntsregex, parse_fontScheme],
/* fmtScheme CT_StyleMatrix */
['fmtScheme', fmtsregex, parse_fmtScheme]
].forEach(function(m) {
if(!(t=data.match(m[1]))) throw m[0] + ' not found in themeElements';
m[2](t, opts);
});
}
var themeltregex = /<a:themeElements([^>]*)>[^\u2603]*<\/a:themeElements>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data, opts) {
/* 20.1.6.9 theme CT_OfficeStyleSheet */
if(!data || data.length === 0) return themes;
var t;
/* themeElements CT_BaseStyles */
if(!(t=data.match(themeltregex))) throw 'themeElements not found in theme';
parse_themeElements(t[0], opts);
return themes;
}
@ -2767,14 +2798,21 @@ function get_cell_style(styles, cell, opts) {
function safe_format(p, fmtid, fillid, opts) {
try {
if(fmtid === 0) {
if(p.t === 'e') p.w = p.w || BErr[p.v];
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v,_ssfopts);
else p.w = SSF._general_num(p.v,_ssfopts);
}
else if(p.t === 'd') {
var dd = datenum(p.v);
if((dd|0) === dd) p.w = SSF._general_int(dd,_ssfopts);
else p.w = SSF._general_num(dd,_ssfopts);
}
else if(p.v === undefined) return "";
else p.w = SSF._general(p.v,_ssfopts);
}
else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
else p.w = SSF.format(fmtid,p.v,_ssfopts);
if(opts.cellNF) p.z = SSF._table[fmtid];
} catch(e) { if(opts.WTF) throw e; }
@ -2875,7 +2913,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:"str",v:undefined};
if(!s[addr]) s[addr] = {t:"stub",v:undefined};
s[addr].l = val;
}
}
@ -2916,9 +2954,19 @@ function write_ws_xml_cols(ws, cols) {
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(cell.v === undefined) return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
switch(cell.t) {
case 'b': vv = cell.v ? "1" : "0"; break;
case 'n': case 'e': vv = ''+cell.v; break;
case 'n': vv = ''+cell.v; break;
case 'e': vv = BErr[cell.v]; break;
case 'd':
if(opts.cellDates) vv = new Date(cell.v).toISOString();
else {
cell.t = 'n';
vv = ''+(cell.v = datenum(cell.v));
if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
}
break;
default: vv = cell.v; break;
}
var v = writetag('v', escapexml(vv)), o = {r:ref};
@ -2927,6 +2975,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(os !== 0) o.s = os;
switch(cell.t) {
case 'n': break;
case 'd': o.t = "d"; break;
case 'b': o.t = "b"; break;
case 'e': o.t = "e"; break;
default:
@ -2936,6 +2985,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
}
o.t = "str"; break;
}
if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
return writextag('c', v, o);
}
@ -2991,7 +3041,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 = "str";
p.t = "stub";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -3005,19 +3055,22 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;
break;
case 'str': if(p.v != null) p.v = utf8read(p.v); else p.v = ""; break;
case 'str':
p.t = "s";
p.v = (p.v!=null) ? utf8read(p.v) : '';
if(opts.cellHTML) p.h = p.v;
break;
case 'inlineStr':
cref = d.match(isregex);
p.t = 'str';
p.t = 's';
if(cref !== null) { sstr = parse_si(cref[1]); p.v = sstr.t; } else p.v = "";
break; // inline string
case 'b': p.v = parsexmlbool(p.v); break;
case 'd':
p.v = datenum(p.v);
p.t = 'n';
if(!opts.cellDates) { p.v = datenum(p.v); p.t = 'n'; }
break;
/* in case of error, stick value in .raw */
case 'e': p.raw = RBErr[p.v]; break;
/* error string in .v, number in .v */
case 'e': p.w = p.v; p.v = RBErr[p.v]; break;
}
/* formatting */
fmtid = fillid = 0;
@ -3255,8 +3308,8 @@ function parse_ws_bin(data, opts, rels) {
case 'n': p.v = val[1]; break;
case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
case 'b': p.v = val[1] ? true : false; break;
case 'e': p.raw = val[1]; p.v = BErr[p.raw]; break;
case 'str': p.v = utf8read(val[1]); break;
case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if(opts.cellFormula && val.length > 3) p.f = val[3];
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
@ -3268,7 +3321,7 @@ function parse_ws_bin(data, opts, rels) {
break;
case 'BrtCellBlank': if(!opts.sheetStubs) break;
p = {t:'str',v:undefined};
p = {t:'s',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;
@ -3290,7 +3343,7 @@ function parse_ws_bin(data, opts, rels) {
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:"str",v:undefined};
if(!s[addr]) s[addr] = {t:'s',v:undefined};
s[addr].l = val;
}
break;
@ -4833,6 +4886,7 @@ var fix_read_opts = fix_opts_func([
['cellHTML', true], /* emit html string as .h */
['cellFormula', true], /* emit formulae as .f */
['cellStyles', false], /* emits style/theme as .s */
['cellDates', false], /* emit date cells with type `d` */
['sheetStubs', false], /* emit empty cells */
['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
@ -4848,6 +4902,8 @@ var fix_read_opts = fix_opts_func([
var fix_write_opts = fix_opts_func([
['cellDates', false], /* write date cells with type `d` */
['bookSST', false], /* Generate Shared String Table */
['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
@ -5234,7 +5290,7 @@ function sheet_to_json(sheet, opts){
v = val.v;
switch(val.t){
case 'e': continue;
case 's': case 'str': break;
case 's': break;
case 'b': case 'n': break;
default: throw 'unrecognized type ' + val.t;
}

10
dist/xlsx.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map vendored

File diff suppressed because one or more lines are too long

80
ods.js

@ -6,7 +6,12 @@ var 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;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../' + 'xlsx').utils;
} catch(e) {
try { return require('./' + 'xlsx').utils; }
catch(ee) { return require('xl' + 'sx').utils; }
}
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
@ -165,7 +170,24 @@ var parse_manifest = function(d, opts) {
}
};
var parse_text_p = function(text, tag) {
return text;
return utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig) {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};
var parse_content_xml = (function() {
@ -193,12 +215,14 @@ var parse_content_xml = (function() {
var textp, textpidx, textptag;
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
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);
if(merges.length) ws['!merges'] = merges;
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
@ -206,16 +230,22 @@ var parse_content_xml = (function() {
sheetag = parsexmltag(Rn[0]);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {};
ws = {}; merges = [];
}
break;
case 'table-row':
case 'table-row': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
++R; C = -1; break; // 9.1.3 <table:table-row>
++R; C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell':
if(Rn[0].charAt(Rn[0].length-2) === '/') { ++C; break; } /* stub */
if(Rn[1]!=='/') {
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0]);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
@ -223,24 +253,32 @@ var parse_content_xml = (function() {
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0]);
q = {t:ctag['value-type'], v:null};
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 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 'currency': 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;
case 'string': q.t = 's'; break;
default: throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 'str') q.v = textp;
if(q.t === 's') q.v = textp;
if(textp) q.w = textp;
ws[get_utils().encode_cell({r:R,c:C})] = q;
if(!(opts.sheetRows && opts.sheetRows < R)) ws[get_utils().encode_cell({r:R,c:C})] = q;
q = null;
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document-content': // 3.1.3.2 <office:document-content>
case 'spreadsheet': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
@ -249,6 +287,13 @@ var parse_content_xml = (function() {
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
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], false]);
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>
@ -334,7 +379,18 @@ var parse_content_xml = (function() {
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'annotation': break;
default: throw Rn;
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': break; // <*:title>
case 'desc': break; // <*:desc>
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
default: if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
@ -346,7 +402,7 @@ var parse_content_xml = (function() {
/* 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'));
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
};
ODS.parse_ods = parse_ods;
})(typeof exports !== 'undefined' ? exports : ODS);

@ -1,5 +1,10 @@
var get_utils = function() {
if(typeof XLSX !== 'undefined') return XLSX.utils;
if(typeof module !== "undefined" && typeof require !== 'undefined') return require('xl' + 'sx').utils;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../' + 'xlsx').utils;
} catch(e) {
try { return require('./' + 'xlsx').utils; }
catch(ee) { return require('xl' + 'sx').utils; }
}
throw new Error("Cannot find XLSX utils");
};

@ -1,3 +1,20 @@
var parse_text_p = function(text, tag) {
return text;
return utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig) {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};

@ -24,12 +24,14 @@ var parse_content_xml = (function() {
var textp, textpidx, textptag;
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
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);
if(merges.length) ws['!merges'] = merges;
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
@ -37,16 +39,22 @@ var parse_content_xml = (function() {
sheetag = parsexmltag(Rn[0]);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {};
ws = {}; merges = [];
}
break;
case 'table-row':
case 'table-row': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
++R; C = -1; break; // 9.1.3 <table:table-row>
++R; C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell':
if(Rn[0].charAt(Rn[0].length-2) === '/') { ++C; break; } /* stub */
if(Rn[1]!=='/') {
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0]);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
@ -54,24 +62,32 @@ var parse_content_xml = (function() {
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0]);
q = {t:ctag['value-type'], v:null};
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 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 'currency': 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;
case 'string': q.t = 's'; break;
default: throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 'str') q.v = textp;
if(q.t === 's') q.v = textp;
if(textp) q.w = textp;
ws[get_utils().encode_cell({r:R,c:C})] = q;
if(!(opts.sheetRows && opts.sheetRows < R)) ws[get_utils().encode_cell({r:R,c:C})] = q;
q = null;
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document-content': // 3.1.3.2 <office:document-content>
case 'spreadsheet': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
@ -80,6 +96,13 @@ var parse_content_xml = (function() {
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
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], false]);
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>
@ -165,7 +188,18 @@ var parse_content_xml = (function() {
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'annotation': break;
default: throw Rn;
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': break; // <*:title>
case 'desc': break; // <*:desc>
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
default: if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,

@ -1,5 +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'));
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
};

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.7.11",
"version": "0.7.12",
"author": "sheetjs",
"description": "Excel 2007+ spreadsheet (XLSB/XLSX/XLSM) and ODS parser and writer",
"keywords": [ "excel", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
@ -10,7 +10,7 @@
"main": "./xlsx",
"dependencies": {
"ssf":"~0.8.1",
"codepage":"~1.3.4",
"codepage":"~1.3.6",
"cfb":">=0.10.0",
"jszip":"2.4.0",
"crc-32":"",

111
test.js

@ -11,7 +11,7 @@ if(process.env.WTF) {
opts.cellStyles = true;
}
var fullex = [".xlsb", ".xlsm", ".xlsx"];
var ex = fullex;
var ex = fullex.slice(); ex.push(".ods");
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"; });
@ -38,14 +38,18 @@ var paths = {
cst2: dir + 'comments_stress_test.xlsb',
fst1: dir + 'formula_stress_test.xlsx',
fst2: dir + 'formula_stress_test.xlsb',
fst3: dir + 'formula_stress_test.ods',
fstb: dir + 'formula_stress_test.xlsb',
hl1: dir + 'hyperlink_stress_test_2011.xlsx',
hl2: dir + 'hyperlink_stress_test_2011.xlsb',
lon1: dir + 'LONumbers.xlsx',
mc1: dir + 'merge_cells.xlsx',
mc2: dir + 'merge_cells.xlsb',
mc3: dir + 'merge_cells.ods',
nf1: dir + 'number_format.xlsm',
nf2: dir + 'number_format.xlsb',
dt1: dir + 'xlsx-stream-d-date-cell.xlsx',
dt2: dir + 'xlsx-stream-d-date-cell.xlsb',
swc1: dir + 'apachepoi_SimpleWithComments.xlsx',
swc2: dir + '2013/apachepoi_SimpleWithComments.xlsx.xlsb'
};
@ -247,6 +251,38 @@ describe('parse options', function() {
});
assert(found);
});
it('should not generate cell dates by default', function() {
var wb = X.readFile(paths.dt1);
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(ws[addr].t !== 'd');
});
});
});
it('XLSB should not generate cell dates', function() {
var wb = X.readFile(paths.dt2, {cellDates: true});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(ws[addr].t !== 'd');
});
});
});
it('XLSX should generate cell dates when requested', function() {
var wb = X.readFile(paths.dt1, {cellDates: true});
var found = false;
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
if(ws[addr].t === 'd') return found = true;
});
});
assert(found);
});
});
describe('sheet', function() {
it('should not generate sheet stubs by default', function() {
@ -254,12 +290,15 @@ describe('parse options', function() {
assert.throws(function() { wb.Sheets.Merge.A2.v; });
wb = X.readFile(paths.mc2);
assert.throws(function() { wb.Sheets.Merge.A2.v; });
wb = X.readFile(paths.mc3);
assert.throws(function() { wb.Sheets.Merge.A2.v; });
});
it('should generate sheet stubs when requested', function() {
var wb = X.readFile(paths.mc1, {sheetStubs:true});
assert(typeof wb.Sheets.Merge.A2.t !== 'undefined');
wb = X.readFile(paths.mc2, {sheetStubs:true});
assert(typeof wb.Sheets.Merge.A2.t !== 'undefined');
/* TODO: ODS */
});
function checkcells(wb, A46, B26, C16, D2) {
assert((typeof wb.Sheets.Text.A46 !== 'undefined') == A46);
@ -272,18 +311,24 @@ describe('parse options', function() {
checkcells(wb, true, true, true, true);
wb = X.readFile(paths.fst2);
checkcells(wb, true, true, true, true);
wb = X.readFile(paths.fst3);
checkcells(wb, true, true, true, true);
});
it('sheetRows n=20', function() {
var wb = X.readFile(paths.fst1, {sheetRows:20});
checkcells(wb, false, false, true, true);
wb = X.readFile(paths.fst2, {sheetRows:20});
checkcells(wb, false, false, true, true);
wb = X.readFile(paths.fst3, {sheetRows:20});
checkcells(wb, false, false, true, true);
});
it('sheetRows n=10', function() {
var wb = X.readFile(paths.fst1, {sheetRows:10});
checkcells(wb, false, false, false, true);
wb = X.readFile(paths.fst2, {sheetRows:10});
checkcells(wb, false, false, false, true);
wb = X.readFile(paths.fst3, {sheetRows:10});
checkcells(wb, false, false, false, true);
});
});
describe('book', function() {
@ -377,7 +422,7 @@ describe('input formats', function() {
describe('output formats', function() {
var wb1, wb2;
before(function() {
X = require('./');
X = require(modp);
wb1 = X.readFile(paths.cp1);
wb2 = X.readFile(paths.cp2);
});
@ -517,12 +562,15 @@ describe('parse features', function() {
X = require(modp);
wb1 = X.readFile(paths.mc1);
wb2 = X.readFile(paths.mc2);
wb3 = X.readFile(paths.mc3);
});
it('should have !merges', function() {
assert(wb1.Sheets.Merge['!merges']);
assert(wb2.Sheets.Merge['!merges']);
var m = [wb1, wb2].map(function(x) { return x.Sheets.Merge['!merges'].map(function(y) { return X.utils.encode_range(y); });});
assert(wb3.Sheets.Merge['!merges']);
var m = [wb1, wb2, wb3].map(function(x) { return x.Sheets.Merge['!merges'].map(function(y) { return X.utils.encode_range(y); });});
assert.deepEqual(m[0].sort(),m[1].sort());
assert.deepEqual(m[0].sort(),m[2].sort());
});
});
@ -550,17 +598,25 @@ describe('parse features', function() {
});
describe('should parse cells with date type (XLSX/XLSM)', function() {
var wb, ws;
before(function() {
X = require('./');
wb = X.readFile(dir+'xlsx-stream-d-date-cell.xlsx');
it('Must have read the date', function() {
var wb, ws;
X = require(modp);
wb = X.readFile(paths.dt1);
var sheetName = 'Sheet1';
ws = wb.Sheets[sheetName];
});
it('Must have read the date', function() {
var sheet = X.utils.sheet_to_row_object_array(ws);
assert.equal(sheet[3]['てすと'], '2/14/14');
});
it('cellDates should not affect formatted text', function() {
var wb1, ws1, wb2, ws2;
var sheetName = 'Sheet1';
X = require(modp);
wb1 = X.readFile(paths.dt1);
ws1 = wb1.Sheets[sheetName];
wb2 = X.readFile(paths.dt2);
ws2 = wb2.Sheets[sheetName];
assert.equal(X.utils.sheet_to_csv(ws1),X.utils.sheet_to_csv(ws2));
});
});
describe('should correctly handle styles', function() {
@ -630,6 +686,13 @@ describe('parse features', function() {
});
});
function seq(end, start) {
var s = start || 0;
var o = new Array(end - s);
for(var i = 0; i != o.length; ++i) o[i] = s + i;
return o;
}
describe('roundtrip features', function() {
before(function() {
X = require(modp);
@ -664,6 +727,36 @@ describe('roundtrip features', function() {
});
});
describe('should preserve dates', function() {
seq(16).forEach(function(n) {
var d = (n & 1) ? 'd' : 'n', dk = d === 'd';
var c = (n & 2) ? 'd' : 'n', dj = c === 'd';
var b = (n & 4) ? 'd' : 'n', di = b === 'd';
var a = (n & 8) ? 'd' : 'n', dh = a === 'd';
var f, sheet, addr;
if(dh) { f = paths.dt1; sheet = 'Sheet1'; addr = 'B5'; }
else { f = paths.nf1; sheet = '2011'; addr = 'J36'; }
it('[' + a + '] -> (' + b + ') -> [' + c + '] -> (' + d + ')', function() {
var wb1 = X.readFile(f, {cellNF: true, cellDates: di, WTF: opts.WTF});
var wb2 = X.read(X.write(wb1, {type:'binary', cellDates:dj, WTF:opts.WTF}), {type:'binary', cellDates: dk, WTF: opts.WTF});
var m = [wb1,wb2].map(function(x) { return x.Sheets[sheet][addr]; });
assert.equal(m[0].w, m[1].w);
/* wb1 cellDates */
if(dh && di) assert.equal(m[0].t, 'd');
//else if(a !== 'd' && di) assert.equal(m[0].t, 'd'); /* TODO */
else assert.equal(m[0].t, 'n');
/* wb2 cellDates */
if(dh && di && dj && dk) assert.equal(m[1].t, 'd');
else if(dj && dk && !di); /* TODO: convert to date */
else assert.equal(m[1].t, 'n');
if(m[0].t === m[1].t) assert.equal(m[0].v, m[1].v);
else if(m[0].t === 'd') assert(Math.abs(datenum(new Date(m[0].v)) - m[1].v)) < .01; /* TODO: 1sec adjustment */
});
});
});
/* the XLSJS require should not cause the test suite to fail */
var XLSJS;
try {

@ -1 +1 @@
Subproject commit 7940cf6da4eb8a4775f5d28a61799772a1e26e6a
Subproject commit b07031a7bd5a8b86b9baac94267f20cf81c6d5eb

@ -1,5 +1,6 @@
AutoFilter.xlsb
BlankSheetTypes.xlsb.pending
ErrorTypes.xlsb
NumberFormatCondition.xlsb
RkNumber.xlsb
calendar_stress_test.xlsb.pending
@ -34,6 +35,7 @@ xlsx-stream-d-date-cell.xlsb
2013/apachepoi_ReadOnlyRecommended.xls.xlsb
2013/apachepoi_testArraysAndTables.xls.xlsb
AutoFilter.xlsx
ErrorTypes.xlsx
LONumbers-2010.xlsx
LONumbers-2011.xlsx
LONumbers.xlsx
@ -104,6 +106,7 @@ apachepoi_54764.xlsx
apachepoi_55640.xlsx
apachepoi_55745.xlsx
apachepoi_55850.xlsx
apachepoi_55864.xlsx
apachepoi_55906-MultiSheetRefs.xlsx
apachepoi_55923.xlsx
apachepoi_55924.xlsx
@ -124,6 +127,7 @@ apachepoi_56688_2.xlsx
apachepoi_56688_3.xlsx
apachepoi_56688_4.xlsx
apachepoi_56702.xlsx
apachepoi_56730.xlsx
apachepoi_56737.xlsx
apachepoi_AverageTaxRates.xlsx
apachepoi_Booleans.xlsx
@ -154,6 +158,7 @@ apachepoi_SimpleMultiCell.xlsx
apachepoi_SimpleWithComments.xlsx
apachepoi_Tables.xlsx
apachepoi_TextFormatTests.xlsx
apachepoi_Themes.xlsx
apachepoi_TwoSheetsNoneHidden.xlsx
apachepoi_TwoSheetsOneHidden.xlsx
apachepoi_WithChart.xlsx
@ -183,6 +188,9 @@ apachepoi_shared_formulas.xlsx
apachepoi_sheetProtection_allLocked.xlsx
apachepoi_sheetProtection_not_protected.xlsx
apachepoi_styles.xlsx
apachepoi_workbookProtection-sheet_password-2013.xlsx
apachepoi_workbookProtection-workbook_password-2013.xlsx
apachepoi_workbookProtection-workbook_password_user_range-2010.xlsx
apachepoi_workbookProtection_not_protected.xlsx
apachepoi_workbookProtection_workbook_revision_protected.xlsx
apachepoi_workbookProtection_workbook_structure_protected.xlsx
@ -311,6 +319,7 @@ spreadsheet-parsexlsx_column-formats.xlsx
spreadsheet-parsexlsx_tab-color.xlsx
sushi.xlsx
text_and_numbers.xlsx
write.xlsx
xlrd_merged_cells.xlsx
xlrd_reveng1.xlsx
xlrd_test_comments_excel.xlsx
@ -329,6 +338,13 @@ number_format_russian.xlsm
numfmt_1_russian.xlsm
openpyxl_r_vba-test.xlsm
pivot_table_test.xlsm
AutoFilter.ods
BlankSheetTypes.ods
cell_style_simple.ods
formula_stress_test.ods
merge_cells.ods
number_format.ods
rich_text_stress.ods
roo_Bibelbund.ods
roo_Bibelbund1.ods
roo_bbu.ods
@ -353,3 +369,4 @@ roo_time-test.ods
roo_type_excel.ods.pending
roo_type_excelx.ods
roo_whitespace.ods
sushi.ods

106
xlsx.js

@ -3,7 +3,7 @@
/*jshint -W041 */
var XLSX = {};
(function(XLSX){
XLSX.version = '0.7.11';
XLSX.version = '0.7.12';
var current_codepage = 1252, current_cptable;
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
@ -2228,7 +2228,7 @@ function parse_fills(t, opts) {
/* Excel uses ARGB strings */
if(y.rgb) fill.fgColor.rgb = y.rgb.substring(y.rgb.length - 6);
break;
case '<bgColor/>': case '</fgColor>': break;
case '<fgColor/>': case '</fgColor>': break;
default: if(opts.WTF) throw 'unrecognized ' + y[0] + ' in fills';
}
@ -2317,7 +2317,7 @@ return function parse_sty_xml(data, opts) {
if((t=data.match(numFmtRegex))) parse_numFmts(t, opts);
/* fonts CT_Fonts ? */
// if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);
/*if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);*/
/* fills CT_Fills */
if((t=data.match(fillsRegex))) parse_fills(t, opts);
@ -2558,16 +2558,47 @@ function parse_clrScheme(t, opts) {
});
}
var clrsregex = /<a:clrScheme([^>]*)>.*<\/a:clrScheme>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data, opts) {
if(!data || data.length === 0) return themes;
/* 20.1.4.1.18 fontScheme CT_FontScheme */
function parse_fontScheme(t, opts) { }
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
function parse_fmtScheme(t, opts) { }
var clrsregex = /<a:clrScheme([^>]*)>[^\u2603]*<\/a:clrScheme>/;
var fntsregex = /<a:fontScheme([^>]*)>[^\u2603]*<\/a:fontScheme>/;
var fmtsregex = /<a:fmtScheme([^>]*)>[^\u2603]*<\/a:fmtScheme>/;
/* 20.1.6.10 themeElements CT_BaseStyles */
function parse_themeElements(data, opts) {
themes.themeElements = {};
var t;
/* clrScheme CT_ColorScheme */
if((t=data.match(clrsregex))) parse_clrScheme(t, opts);
[
/* clrScheme CT_ColorScheme */
['clrScheme', clrsregex, parse_clrScheme],
/* fontScheme CT_FontScheme */
['fontScheme', fntsregex, parse_fontScheme],
/* fmtScheme CT_StyleMatrix */
['fmtScheme', fmtsregex, parse_fmtScheme]
].forEach(function(m) {
if(!(t=data.match(m[1]))) throw m[0] + ' not found in themeElements';
m[2](t, opts);
});
}
var themeltregex = /<a:themeElements([^>]*)>[^\u2603]*<\/a:themeElements>/;
/* 14.2.7 Theme Part */
function parse_theme_xml(data, opts) {
/* 20.1.6.9 theme CT_OfficeStyleSheet */
if(!data || data.length === 0) return themes;
var t;
/* themeElements CT_BaseStyles */
if(!(t=data.match(themeltregex))) throw 'themeElements not found in theme';
parse_themeElements(t[0], opts);
return themes;
}
@ -2767,14 +2798,21 @@ function get_cell_style(styles, cell, opts) {
function safe_format(p, fmtid, fillid, opts) {
try {
if(fmtid === 0) {
if(p.t === 'e') p.w = p.w || BErr[p.v];
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v,_ssfopts);
else p.w = SSF._general_num(p.v,_ssfopts);
}
else if(p.t === 'd') {
var dd = datenum(p.v);
if((dd|0) === dd) p.w = SSF._general_int(dd,_ssfopts);
else p.w = SSF._general_num(dd,_ssfopts);
}
else if(p.v === undefined) return "";
else p.w = SSF._general(p.v,_ssfopts);
}
else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
else p.w = SSF.format(fmtid,p.v,_ssfopts);
if(opts.cellNF) p.z = SSF._table[fmtid];
} catch(e) { if(opts.WTF) throw e; }
@ -2875,7 +2913,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:"str",v:undefined};
if(!s[addr]) s[addr] = {t:"stub",v:undefined};
s[addr].l = val;
}
}
@ -2916,9 +2954,19 @@ function write_ws_xml_cols(ws, cols) {
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(cell.v === undefined) return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
switch(cell.t) {
case 'b': vv = cell.v ? "1" : "0"; break;
case 'n': case 'e': vv = ''+cell.v; break;
case 'n': vv = ''+cell.v; break;
case 'e': vv = BErr[cell.v]; break;
case 'd':
if(opts.cellDates) vv = new Date(cell.v).toISOString();
else {
cell.t = 'n';
vv = ''+(cell.v = datenum(cell.v));
if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
}
break;
default: vv = cell.v; break;
}
var v = writetag('v', escapexml(vv)), o = {r:ref};
@ -2927,6 +2975,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
if(os !== 0) o.s = os;
switch(cell.t) {
case 'n': break;
case 'd': o.t = "d"; break;
case 'b': o.t = "b"; break;
case 'e': o.t = "e"; break;
default:
@ -2936,6 +2985,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
}
o.t = "str"; break;
}
if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
return writextag('c', v, o);
}
@ -2991,7 +3041,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 = "str";
p.t = "stub";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -3005,19 +3055,22 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;
break;
case 'str': if(p.v != null) p.v = utf8read(p.v); else p.v = ""; break;
case 'str':
p.t = "s";
p.v = (p.v!=null) ? utf8read(p.v) : '';
if(opts.cellHTML) p.h = p.v;
break;
case 'inlineStr':
cref = d.match(isregex);
p.t = 'str';
p.t = 's';
if(cref !== null) { sstr = parse_si(cref[1]); p.v = sstr.t; } else p.v = "";
break; // inline string
case 'b': p.v = parsexmlbool(p.v); break;
case 'd':
p.v = datenum(p.v);
p.t = 'n';
if(!opts.cellDates) { p.v = datenum(p.v); p.t = 'n'; }
break;
/* in case of error, stick value in .raw */
case 'e': p.raw = RBErr[p.v]; break;
/* error string in .v, number in .v */
case 'e': p.w = p.v; p.v = RBErr[p.v]; break;
}
/* formatting */
fmtid = fillid = 0;
@ -3255,8 +3308,8 @@ function parse_ws_bin(data, opts, rels) {
case 'n': p.v = val[1]; break;
case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
case 'b': p.v = val[1] ? true : false; break;
case 'e': p.raw = val[1]; p.v = BErr[p.raw]; break;
case 'str': p.v = utf8read(val[1]); break;
case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if(opts.cellFormula && val.length > 3) p.f = val[3];
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
@ -3268,7 +3321,7 @@ function parse_ws_bin(data, opts, rels) {
break;
case 'BrtCellBlank': if(!opts.sheetStubs) break;
p = {t:'str',v:undefined};
p = {t:'s',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;
@ -3290,7 +3343,7 @@ function parse_ws_bin(data, opts, rels) {
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:"str",v:undefined};
if(!s[addr]) s[addr] = {t:'s',v:undefined};
s[addr].l = val;
}
break;
@ -4814,7 +4867,7 @@ 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 module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
return ODS.parse_ods(zip, opts);
}
@ -4833,6 +4886,7 @@ var fix_read_opts = fix_opts_func([
['cellHTML', true], /* emit html string as .h */
['cellFormula', true], /* emit formulae as .f */
['cellStyles', false], /* emits style/theme as .s */
['cellDates', false], /* emit date cells with type `d` */
['sheetStubs', false], /* emit empty cells */
['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
@ -4848,6 +4902,8 @@ var fix_read_opts = fix_opts_func([
var fix_write_opts = fix_opts_func([
['cellDates', false], /* write date cells with type `d` */
['bookSST', false], /* Generate Shared String Table */
['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
@ -5234,7 +5290,7 @@ function sheet_to_json(sheet, opts){
v = val.v;
switch(val.t){
case 'e': continue;
case 's': case 'str': break;
case 's': break;
case 'b': case 'n': break;
default: throw 'unrecognized type ' + val.t;
}