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:
parent
61d2e55cc6
commit
f9097d403b
@ -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/
|
||||
|
90
README.md
90
README.md
@ -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
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
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);
|
||||
|
8
dist/xlsx.core.min.js
vendored
8
dist/xlsx.core.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.core.min.map
vendored
2
dist/xlsx.core.min.map
vendored
File diff suppressed because one or more lines are too long
10
dist/xlsx.full.min.js
vendored
10
dist/xlsx.full.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.full.min.map
vendored
2
dist/xlsx.full.min.map
vendored
File diff suppressed because one or more lines are too long
104
dist/xlsx.js
vendored
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
10
dist/xlsx.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.min.map
vendored
2
dist/xlsx.min.map
vendored
File diff suppressed because one or more lines are too long
80
ods.js
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));
|
||||
}
|
||||