forked from sheetjs/sheetjs
version bump 0.18.3
- XLSX / XLSB dynamic array formulae - use Uint8Array when available in write (fixes #2539 h/t @RScherzer) - mini build cleanup to satiate webpack (fixes #2526 #2530)
This commit is contained in:
parent
4f6a849a59
commit
e14aee3e51
|
@ -41,6 +41,7 @@ ExtendScript
|
|||
IndexedDB
|
||||
JavaScriptCore
|
||||
LocalStorage
|
||||
NestJS
|
||||
NPM
|
||||
Nuxt.js
|
||||
Redis
|
||||
|
|
7
Makefile
7
Makefile
|
@ -18,6 +18,7 @@ ESMJSDEPS=$(shell cat misc/mjs.lst)
|
|||
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
|
||||
DEPS=$(sort $(wildcard bits/*.js))
|
||||
TSBITS=$(patsubst modules/%,bits/%,$(wildcard modules/[0-9][0-9]_*.js))
|
||||
MTSBITS=$(patsubst modules/%,misc/%,$(wildcard modules/[0-9][0-9]_*.js))
|
||||
TARGET=$(LIB).js
|
||||
FLOWTARGET=$(LIB).flow.js
|
||||
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
|
||||
|
@ -52,6 +53,9 @@ bits/18_cfb.js: node_modules/cfb/xlscfb.flow.js
|
|||
$(TSBITS): bits/%: modules/%
|
||||
cp $^ $@
|
||||
|
||||
$(MTSBITS): misc/%: modules/%
|
||||
cp $^ $@
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Remove targets and build artifacts
|
||||
|
@ -82,6 +86,7 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution
|
|||
uglifyjs $(REQS) dist/$(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)"
|
||||
misc/strip_sourcemap.sh dist/$(LIB).core.min.js
|
||||
@# full
|
||||
#cat <(head -n 1 bits/00_header.js) $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) > dist/$(LIB).full.js
|
||||
uglifyjs $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) $(UGLIFYOPTS) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
|
||||
misc/strip_sourcemap.sh dist/$(LIB).full.min.js
|
||||
@# mini
|
||||
|
@ -101,7 +106,7 @@ dist-deps: ## Copy dependencies for distribution
|
|||
aux: $(AUXTARGETS)
|
||||
|
||||
BYTEFILEC=dist/xlsx.{full,core,mini}.min.js
|
||||
BYTEFILER=dist/xlsx.extendscript.js
|
||||
BYTEFILER=dist/xlsx.extendscript.js xlsx.mjs
|
||||
.PHONY: bytes
|
||||
bytes: ## Display minified and gzipped file sizes
|
||||
@for i in $(BYTEFILEC); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
|
||||
|
|
572
README.md
572
README.md
|
@ -24,12 +24,8 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
|
|||
|
||||
![circo graph of format support](formats.png)
|
||||
|
||||
<details><summary><b>Diagram Legend</b> (click to show)</summary>
|
||||
|
||||
![graph legend](legend.png)
|
||||
|
||||
</details>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
<details>
|
||||
|
@ -46,14 +42,17 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
|
|||
* [Parsing Workbooks](#parsing-workbooks)
|
||||
* [Processing JSON and JS Data](#processing-json-and-js-data)
|
||||
* [Processing HTML Tables](#processing-html-tables)
|
||||
- [Working with the Workbook](#working-with-the-workbook)
|
||||
* [Parsing and Writing Examples](#parsing-and-writing-examples)
|
||||
- [Processing Data](#processing-data)
|
||||
* [Modifying Workbook Structure](#modifying-workbook-structure)
|
||||
* [Modifying Cell Values](#modifying-cell-values)
|
||||
* [Modifying Other Worksheet / Workbook / Cell Properties](#modifying-other-worksheet--workbook--cell-properties)
|
||||
- [Packaging and Releasing Data](#packaging-and-releasing-data)
|
||||
* [Writing Workbooks](#writing-workbooks)
|
||||
* [Writing Examples](#writing-examples)
|
||||
* [Streaming Write](#streaming-write)
|
||||
* [Generating JSON and JS Data](#generating-json-and-js-data)
|
||||
* [Generating HTML Tables](#generating-html-tables)
|
||||
* [Generating Single-Worksheet Snapshots](#generating-single-worksheet-snapshots)
|
||||
- [Interface](#interface)
|
||||
* [Parsing functions](#parsing-functions)
|
||||
* [Writing functions](#writing-functions)
|
||||
|
@ -150,10 +149,11 @@ For example, `unpkg` makes the latest version available at:
|
|||
|
||||
The complete single-file version is generated at `dist/xlsx.full.min.js`
|
||||
|
||||
`dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings)
|
||||
|
||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
|
||||
- codepage library skipped (no support for XLS encodings)
|
||||
- XLSX compression option not currently available
|
||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003
|
||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
|
||||
- node stream utils removed
|
||||
|
||||
</details>
|
||||
|
@ -317,6 +317,18 @@ and approaches for steps 1 and 5.
|
|||
|
||||
Utility functions help with step 3.
|
||||
|
||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
|
||||
solutions for common data import scenarios.
|
||||
|
||||
["Packaging and Releasing Data"](#packaging-and-releasing-data) describes
|
||||
solutions for common data export scenarios.
|
||||
|
||||
["Processing Data"](#packaging-and-releasing-data) describes solutions for
|
||||
common workbook processing and manipulation scenarios.
|
||||
|
||||
["Utility Functions"](#utility-functions) details utility functions for
|
||||
translating JSON Arrays and other common JS structures into worksheet objects.
|
||||
|
||||
### The Zen of SheetJS
|
||||
|
||||
_Data processing should fit in any workflow_
|
||||
|
@ -325,15 +337,6 @@ The library does not impose a separate lifecycle. It fits nicely in websites
|
|||
and apps built using any framework. The plain JS data objects play nice with
|
||||
Web Workers and future APIs.
|
||||
|
||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
|
||||
solutions for common data import scenarios.
|
||||
|
||||
["Writing Workbooks"](#writing-workbooks) describes solutions for common data
|
||||
export scenarios involving actual spreadsheet files.
|
||||
|
||||
["Utility Functions"](#utility-functions) details utility functions for
|
||||
translating JSON Arrays and other common JS structures into worksheet objects.
|
||||
|
||||
_JavaScript is a powerful language for data processing_
|
||||
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
|
||||
|
@ -576,6 +579,12 @@ The [`demos` directory](demos/) includes sample projects for:
|
|||
|
||||
Other examples are included in the [showcase](demos/showcase/).
|
||||
|
||||
<https://sheetjs.com/demos/modify.html> shows a complete example of reading,
|
||||
modifying, and writing files.
|
||||
|
||||
<https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line
|
||||
tool included with node installations, reading spreadsheet files and exporting
|
||||
the contents in various formats.
|
||||
## Acquiring and Extracting Data
|
||||
|
||||
### Parsing Workbooks
|
||||
|
@ -1018,12 +1027,13 @@ const workbook = XLSX.read(data);
|
|||
</details>
|
||||
|
||||
More detailed examples are covered in the [included demos](demos/)
|
||||
|
||||
### Processing JSON and JS Data
|
||||
|
||||
JSON and JS data tend to represent single worksheets. This section will use a
|
||||
few utility functions to generate workbooks:
|
||||
few utility functions to generate workbooks.
|
||||
|
||||
_Create a new Worksheet_
|
||||
_Create a new Workbook_
|
||||
|
||||
```js
|
||||
var workbook = XLSX.utils.book_new();
|
||||
|
@ -1031,16 +1041,9 @@ var workbook = XLSX.utils.book_new();
|
|||
|
||||
The `book_new` utility function creates an empty workbook with no worksheets.
|
||||
|
||||
|
||||
_Append a Worksheet to a Workbook_
|
||||
|
||||
```js
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
|
||||
```
|
||||
|
||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
|
||||
The third argument specifies the desired worksheet name. Multiple worksheets can
|
||||
be added to a workbook by calling the function multiple times.
|
||||
Spreadsheet software generally require at least one worksheet and enforce the
|
||||
requirement in the user interface. This library enforces the requirement at
|
||||
write time, throwing errors if an empty workbook is passed to write functions.
|
||||
|
||||
|
||||
**API**
|
||||
|
@ -1053,14 +1056,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
|
|||
|
||||
The `aoa_to_sheet` utility function walks an "array of arrays" in row-major
|
||||
order, generating a worksheet object. The following snippet generates a sheet
|
||||
with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc:
|
||||
with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
["A1", "B1", "C1"],
|
||||
["A2", "B2", "C2"],
|
||||
["A3", "B3", "C3"]
|
||||
])
|
||||
]);
|
||||
```
|
||||
|
||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
|
||||
|
@ -1361,41 +1364,57 @@ const workbook = XLSX.utils.table_to_book(doc);
|
|||
|
||||
</details>
|
||||
|
||||
## Working with the Workbook
|
||||
## Processing Data
|
||||
|
||||
The full object format is described later in this README.
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
|
||||
representation of the core concepts of a workbook. The utility functions work
|
||||
with the object representation and are intended to handle common use cases.
|
||||
|
||||
<details>
|
||||
<summary><b>Reading a specific cell </b> (click to show)</summary>
|
||||
### Modifying Workbook Structure
|
||||
|
||||
This example extracts the value stored in cell A1 from the first worksheet:
|
||||
**API**
|
||||
|
||||
_Append a Worksheet to a Workbook_
|
||||
|
||||
```js
|
||||
var first_sheet_name = workbook.SheetNames[0];
|
||||
var address_of_cell = 'A1';
|
||||
|
||||
/* Get worksheet */
|
||||
var worksheet = workbook.Sheets[first_sheet_name];
|
||||
|
||||
/* Find desired cell */
|
||||
var desired_cell = worksheet[address_of_cell];
|
||||
|
||||
/* Get the value */
|
||||
var desired_value = (desired_cell ? desired_cell.v : undefined);
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
|
||||
```
|
||||
|
||||
</details>
|
||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
|
||||
The third argument specifies the desired worksheet name. Multiple worksheets can
|
||||
be added to a workbook by calling the function multiple times.
|
||||
|
||||
_List the Worksheet names in tab order_
|
||||
|
||||
```js
|
||||
var wsnames = workbook.SheetNames;
|
||||
```
|
||||
|
||||
The `SheetNames` property of the workbook object is a list of the worksheet
|
||||
names in "tab order". API functions will look at this array.
|
||||
|
||||
_Replace a Worksheet in place_
|
||||
|
||||
```js
|
||||
workbook.Sheets[sheet_name] = new_worksheet;
|
||||
```
|
||||
|
||||
The `Sheets` property of the workbook object is an object whose keys are names
|
||||
and whose values are worksheet objects. By reassigning to a property of the
|
||||
`Sheets` object, the worksheet object can be changed without disrupting the
|
||||
rest of the worksheet structure.
|
||||
|
||||
**Examples**
|
||||
|
||||
<details>
|
||||
<summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary>
|
||||
<summary><b>Add a new worksheet to a workbook</b> (click to show)</summary>
|
||||
|
||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
|
||||
sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
|
||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input).
|
||||
|
||||
```js
|
||||
var ws_name = "SheetJS";
|
||||
|
||||
/* make worksheet */
|
||||
/* Create worksheet */
|
||||
var ws_data = [
|
||||
[ "S", "h", "e", "e", "t", "J", "S" ],
|
||||
[ 1 , 2 , 3 , 4 , 5 ]
|
||||
|
@ -1408,41 +1427,60 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name);
|
|||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Creating a new workbook from scratch</b> (click to show)</summary>
|
||||
### Modifying Cell Values
|
||||
|
||||
The workbook object contains a `SheetNames` array of names and a `Sheets` object
|
||||
mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
|
||||
creates a new workbook object:
|
||||
**API**
|
||||
|
||||
_Modify a single cell value in a worksheet_
|
||||
|
||||
```js
|
||||
/* create a new blank workbook */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address });
|
||||
```
|
||||
|
||||
The new workbook is blank and contains no worksheets. The write functions will
|
||||
error if the workbook is empty.
|
||||
_Modify multiple cell values in a worksheet_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, aoa, opts);
|
||||
```
|
||||
|
||||
The `sheet_add_aoa` utility function modifies cell values in a worksheet. The
|
||||
first argument is the worksheet object. The second argument is an array of
|
||||
arrays of values. The `origin` key of the third argument controls where cells
|
||||
will be written. The following snippet sets `B3=1` and `E5="abc"`:
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
[1], // <-- Write 1 to cell B3
|
||||
, // <-- Do nothing in row 4
|
||||
[/*B5*/, /*C5*/, /*D5*/, "abc"] // <-- Write "abc" to cell E5
|
||||
], { origin: "B3" });
|
||||
```
|
||||
|
||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
|
||||
optional `opts` argument in more detail.
|
||||
|
||||
**Examples**
|
||||
|
||||
<details>
|
||||
<summary><b>Appending rows to a worksheet</b> (click to show)</summary>
|
||||
|
||||
The special origin value `-1` instructs `sheet_add_aoa` to start in column A of
|
||||
the row after the last row in the range, appending the data:
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
["first row after data", 1],
|
||||
["second row after data", 2]
|
||||
], { origin: -1 });
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### Parsing and Writing Examples
|
||||
### Modifying Other Worksheet / Workbook / Cell Properties
|
||||
|
||||
- <https://sheetjs.com/demos/modify.html> read + modify + write files
|
||||
|
||||
- <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node
|
||||
|
||||
The node version installs a command line tool `xlsx` which can read spreadsheet
|
||||
files and output the contents in various formats. The source is available at
|
||||
`xlsx.njs` in the bin directory.
|
||||
|
||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
|
||||
|
||||
- `XLSX.utils.sheet_to_csv` generates CSV
|
||||
- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
|
||||
- `XLSX.utils.sheet_to_html` generates HTML
|
||||
- `XLSX.utils.sheet_to_json` generates an array of objects
|
||||
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes
|
||||
the object structures in greater detail.
|
||||
|
||||
## Packaging and Releasing Data
|
||||
|
||||
|
@ -1963,6 +2001,45 @@ The [`vuejs` demo](demos/vue) includes more React examples.
|
|||
|
||||
</details>
|
||||
|
||||
### Generating Single-Worksheet Snapshots
|
||||
|
||||
The `sheet_to_*` functions accept a worksheet object.
|
||||
|
||||
**API**
|
||||
|
||||
_Generate a CSV from a single worksheet_
|
||||
|
||||
```js
|
||||
var csv = XLSX.utils.sheet_to_csv(worksheet, opts);
|
||||
```
|
||||
|
||||
This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type.
|
||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
|
||||
function and the optional `opts` argument in more detail.
|
||||
|
||||
_Generate "Text" from a single worksheet_
|
||||
|
||||
```js
|
||||
var txt = XLSX.utils.sheet_to_txt(worksheet, opts);
|
||||
```
|
||||
|
||||
This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type.
|
||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
|
||||
function and the optional `opts` argument in more detail.
|
||||
|
||||
_Generate a list of formulae from a single worksheet_
|
||||
|
||||
```js
|
||||
var fmla = XLSX.utils.sheet_to_formulae(worksheet);
|
||||
```
|
||||
|
||||
This snapshot generates an array of entries representing the embedded formulae.
|
||||
Array formulae are rendered in the form `range=formula` while plain cells are
|
||||
rendered in the form `cell=formula or value`. String literals are prefixed with
|
||||
an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
|
||||
["Formulae Output"](#formulae-output) describes the function in more detail.
|
||||
|
||||
## Interface
|
||||
|
||||
`XLSX` is the exposed variable in the browser and the exported node variable
|
||||
|
@ -2065,6 +2142,7 @@ Cell objects are plain JS objects with keys and values following the convention:
|
|||
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
|
||||
| `f` | cell formula encoded as an A1-style string (if applicable) |
|
||||
| `F` | range of enclosing array if formula is array formula (if applicable) |
|
||||
| `D` | if true, array formula is dynamic (if applicable) |
|
||||
| `r` | rich text encoding (if applicable) |
|
||||
| `h` | HTML rendering of the rich text (if applicable) |
|
||||
| `c` | comments associated with the cell |
|
||||
|
@ -2416,79 +2494,7 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
|
|||
do not start with `=`.
|
||||
|
||||
<details>
|
||||
<summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
{
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:1 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', v:3, f:'A1+A2' }
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
Shared formulae are decompressed and each cell has the formula corresponding to
|
||||
its cell. Writers generally do not attempt to generate shared formulae.
|
||||
|
||||
Cells with formula entries but no value will be serialized in a way that Excel
|
||||
and other spreadsheet tools will recognize. This library will not automatically
|
||||
compute formula results! For example, to compute `BESSELJ` in a worksheet:
|
||||
|
||||
<details>
|
||||
<summary><b>Formula without known value</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
{
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:3.14159 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', f:'BESSELJ(A1,A2)' }
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
**Array Formulae**
|
||||
|
||||
Array formulae are stored in the top-left cell of the array block. All cells
|
||||
of an array formula have a `F` field corresponding to the range. A single-cell
|
||||
formula can be distinguished from a plain formula by the presence of `F` field.
|
||||
|
||||
<details>
|
||||
<summary><b>Array Formula examples</b> (click to show)</summary>
|
||||
|
||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
|
||||
|
||||
```js
|
||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
|
||||
```
|
||||
|
||||
For a multi-cell array formula, every cell has the same array range but only the
|
||||
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
|
||||
|
||||
```js
|
||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
|
||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
|
||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Utilities and writers are expected to check for the presence of a `F` field and
|
||||
ignore any possible formula element `f` in cells other than the starting cell.
|
||||
They are not expected to perform validation of the formulae!
|
||||
|
||||
<details>
|
||||
<summary><b>Formula Output Utility Function</b> (click to show)</summary>
|
||||
|
||||
The `sheet_to_formulae` method generates one line per formula or array formula.
|
||||
Array formulae are rendered in the form `range=formula` while plain cells are
|
||||
rendered in the form `cell=formula or value`. Note that string literals are
|
||||
prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Formulae File Format Details</b> (click to show)</summary>
|
||||
<summary><b>Formulae File Format Support</b> (click to show)</summary>
|
||||
|
||||
| Storage Representation | Formats | Read | Write |
|
||||
|:-----------------------|:-------------------------|:-----:|:-----:|
|
||||
|
@ -2502,6 +2508,272 @@ Since Excel prohibits named cells from colliding with names of A1 or RC style
|
|||
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
|
||||
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
|
||||
formulae can be converted with regular expressions.
|
||||
|
||||
Shared formulae are decompressed and each cell has the formula corresponding to
|
||||
its cell. Writers generally do not attempt to generate shared formulae.
|
||||
</details>
|
||||
|
||||
**Single-Cell Formulae**
|
||||
|
||||
For simple formulae, the `f` key of the desired cell can be set to the actual
|
||||
formula text. This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
|
||||
|
||||
```js
|
||||
var worksheet = {
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:1 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', v:3, f:'A1+A2' }
|
||||
};
|
||||
```
|
||||
|
||||
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
[ 1 ], // A1
|
||||
[ 2 ], // A2
|
||||
[ {t: "n", v: 3, f: "A1+A2"} ] // A3
|
||||
]);
|
||||
```
|
||||
|
||||
Cells with formula entries but no value will be serialized in a way that Excel
|
||||
and other spreadsheet tools will recognize. This library will not automatically
|
||||
compute formula results! For example, the following worksheet will include the
|
||||
`BESSELJ` function but the result will not be available in JavaScript:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
[ 3.14159, 2 ], // Row "1"
|
||||
[ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
|
||||
}
|
||||
```
|
||||
|
||||
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
|
||||
offers a formula calculator component for evaluating expressions, updating
|
||||
values and dependent cells, and refreshing entire workbooks.
|
||||
|
||||
|
||||
**Array Formulae**
|
||||
|
||||
_Assign an array formula_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
|
||||
```
|
||||
|
||||
Array formulae are stored in the top-left cell of the array block. All cells
|
||||
of an array formula have a `F` field corresponding to the range. A single-cell
|
||||
formula can be distinguished from a plain formula by the presence of `F` field.
|
||||
|
||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
|
||||
```
|
||||
|
||||
For a multi-cell array formula, every cell has the same array range but only the
|
||||
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
|
||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
|
||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
|
||||
```
|
||||
|
||||
Utilities and writers are expected to check for the presence of a `F` field and
|
||||
ignore any possible formula element `f` in cells other than the starting cell.
|
||||
They are not expected to perform validation of the formulae!
|
||||
|
||||
|
||||
**Dynamic Array Formulae**
|
||||
|
||||
_Assign a dynamic array formula_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
|
||||
```
|
||||
|
||||
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
|
||||
file formats. They are represented like normal array formulae but have special
|
||||
cell metadata indicating that the formula should be allowed to adjust the range.
|
||||
|
||||
An array formula can be marked as dynamic by setting the cell's `D` property to
|
||||
true. The `F` range is expected but can be the set to the current cell:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
|
||||
```
|
||||
|
||||
**Localization with Function Names**
|
||||
|
||||
SheetJS operates at the file level. Excel stores formula expressions using the
|
||||
English (United States) function names. For non-English users, Excel uses a
|
||||
localized set of function names.
|
||||
|
||||
For example, when the computer language and region is set to French (France),
|
||||
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function. However,
|
||||
in the actual file, Excel stores `SUM(A1:C3)`.
|
||||
|
||||
**Prefixed "Future Functions"**
|
||||
|
||||
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
|
||||
stored in files. When writing formula expressions using these functions, the
|
||||
prefix is required for maximal compatibility:
|
||||
|
||||
```js
|
||||
// Broadest compatibility
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
|
||||
|
||||
// Can cause errors in spreadsheet software
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
|
||||
```
|
||||
|
||||
When reading a file, the `xlfn` option preserves the prefixes.
|
||||
|
||||
<details>
|
||||
<summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary>
|
||||
|
||||
This list is growing with each Excel release.
|
||||
|
||||
```
|
||||
ACOT
|
||||
ACOTH
|
||||
AGGREGATE
|
||||
ARABIC
|
||||
BASE
|
||||
BETA.DIST
|
||||
BETA.INV
|
||||
BINOM.DIST
|
||||
BINOM.DIST.RANGE
|
||||
BINOM.INV
|
||||
BITAND
|
||||
BITLSHIFT
|
||||
BITOR
|
||||
BITRSHIFT
|
||||
BITXOR
|
||||
BYCOL
|
||||
BYROW
|
||||
CEILING.MATH
|
||||
CEILING.PRECISE
|
||||
CHISQ.DIST
|
||||
CHISQ.DIST.RT
|
||||
CHISQ.INV
|
||||
CHISQ.INV.RT
|
||||
CHISQ.TEST
|
||||
COMBINA
|
||||
CONFIDENCE.NORM
|
||||
CONFIDENCE.T
|
||||
COT
|
||||
COTH
|
||||
COVARIANCE.P
|
||||
COVARIANCE.S
|
||||
CSC
|
||||
CSCH
|
||||
DAYS
|
||||
DECIMAL
|
||||
ERF.PRECISE
|
||||
ERFC.PRECISE
|
||||
EXPON.DIST
|
||||
F.DIST
|
||||
F.DIST.RT
|
||||
F.INV
|
||||
F.INV.RT
|
||||
F.TEST
|
||||
FIELDVALUE
|
||||
FILTERXML
|
||||
FLOOR.MATH
|
||||
FLOOR.PRECISE
|
||||
FORMULATEXT
|
||||
GAMMA
|
||||
GAMMA.DIST
|
||||
GAMMA.INV
|
||||
GAMMALN.PRECISE
|
||||
GAUSS
|
||||
HYPGEOM.DIST
|
||||
IFNA
|
||||
IMCOSH
|
||||
IMCOT
|
||||
IMCSC
|
||||
IMCSCH
|
||||
IMSEC
|
||||
IMSECH
|
||||
IMSINH
|
||||
IMTAN
|
||||
ISFORMULA
|
||||
ISOMITTED
|
||||
ISOWEEKNUM
|
||||
LAMBDA
|
||||
LET
|
||||
LOGNORM.DIST
|
||||
LOGNORM.INV
|
||||
MAKEARRAY
|
||||
MAP
|
||||
MODE.MULT
|
||||
MODE.SNGL
|
||||
MUNIT
|
||||
NEGBINOM.DIST
|
||||
NORM.DIST
|
||||
NORM.INV
|
||||
NORM.S.DIST
|
||||
NORM.S.INV
|
||||
NUMBERVALUE
|
||||
PDURATION
|
||||
PERCENTILE.EXC
|
||||
PERCENTILE.INC
|
||||
PERCENTRANK.EXC
|
||||
PERCENTRANK.INC
|
||||
PERMUTATIONA
|
||||
PHI
|
||||
POISSON.DIST
|
||||
QUARTILE.EXC
|
||||
QUARTILE.INC
|
||||
QUERYSTRING
|
||||
RANDARRAY
|
||||
RANK.AVG
|
||||
RANK.EQ
|
||||
REDUCE
|
||||
RRI
|
||||
SCAN
|
||||
SEC
|
||||
SECH
|
||||
SEQUENCE
|
||||
SHEET
|
||||
SHEETS
|
||||
SKEW.P
|
||||
SORTBY
|
||||
STDEV.P
|
||||
STDEV.S
|
||||
T.DIST
|
||||
T.DIST.2T
|
||||
T.DIST.RT
|
||||
T.INV
|
||||
T.INV.2T
|
||||
T.TEST
|
||||
UNICHAR
|
||||
UNICODE
|
||||
UNIQUE
|
||||
VAR.P
|
||||
VAR.S
|
||||
WEBSERVICE
|
||||
WEIBULL.DIST
|
||||
XLOOKUP
|
||||
XOR
|
||||
Z.TEST
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### Row and Column Properties
|
||||
|
|
|
@ -129,6 +129,7 @@ function wb_fmt() {
|
|||
seen = true;
|
||||
opts.cellFormula = true;
|
||||
opts.cellNF = true;
|
||||
opts.xlfn = true;
|
||||
if(program.output) sheetname = program.output;
|
||||
}
|
||||
function isfmt(m/*:string*/)/*:boolean*/ {
|
||||
|
|
|
@ -1 +1 @@
|
|||
XLSX.version = '0.18.2';
|
||||
XLSX.version = '0.18.3';
|
||||
|
|
|
@ -13,7 +13,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
|||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
if(typeof Deno !== 'undefined') {
|
||||
/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
|
||||
if(enc) switch(enc) {
|
||||
if(enc && typeof payload == "string") switch(enc) {
|
||||
case "utf8": payload = new TextEncoder(enc).encode(payload); break;
|
||||
case "binary": payload = s2ab(payload); break;
|
||||
/* TODO: binary equivalent */
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
function parse_Int32LE(data) {
|
||||
return data.read_shift(4, 'i');
|
||||
}
|
||||
function write_UInt32LE(x/*:number*/, o) {
|
||||
if (!o) o = new_buf(4);
|
||||
o.write_shift(4, x);
|
||||
|
|
|
@ -61,8 +61,8 @@ var ct2type/*{[string]:string}*/ = ({
|
|||
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
|
||||
|
||||
/* Metadata */
|
||||
"application/vnd.ms-excel.sheetMetadata": "TODO",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
|
||||
"application/vnd.ms-excel.sheetMetadata": "metadata",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
|
||||
|
||||
/* PivotCache */
|
||||
"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
|
||||
|
@ -179,6 +179,10 @@ var CT_LIST = (function(){
|
|||
xlsx: "application/vnd.ms-excel.macrosheet+xml",
|
||||
xlsb: "application/vnd.ms-excel.macrosheet"
|
||||
},
|
||||
metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
|
||||
xlsb: "application/vnd.ms-excel.sheetMetadata"
|
||||
},
|
||||
styles: { /* Styles */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
||||
xlsb: "application/vnd.ms-excel.styles"
|
||||
|
@ -198,7 +202,7 @@ function new_ct()/*:any*/ {
|
|||
workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
|
||||
rels:[], strs:[], comments:[], links:[],
|
||||
coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
|
||||
calcchains:[], vba: [], drawings: [],
|
||||
calcchains:[], vba: [], drawings: [], metadata: [],
|
||||
TODO:[], xmlns: "" }/*:any*/);
|
||||
}
|
||||
|
||||
|
@ -297,6 +301,7 @@ function write_ct(ct, opts)/*:string*/ {
|
|||
f3('vba');
|
||||
f3('comments');
|
||||
f3('drawings');
|
||||
f2('metadata');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
||||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
|
@ -870,7 +870,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
|
|||
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
|
||||
var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
|
||||
/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
|
||||
if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
|
||||
if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
|
||||
stack.push(name);
|
||||
break;
|
||||
|
||||
|
|
|
@ -300,6 +300,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
|
|||
}
|
||||
if(cell.l) ws['!links'].push([ref, cell.l]);
|
||||
if(cell.c) ws['!comments'].push([ref, cell.c]);
|
||||
if(cell.D) o.cm = 1;
|
||||
return writextag('c', v, o);
|
||||
}
|
||||
|
||||
|
@ -476,6 +477,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
|
|||
}
|
||||
safe_format(p, fmtid, fillid, opts, themes, styles);
|
||||
if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
|
||||
if(tag.cm && opts.xlmeta) {
|
||||
var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
|
||||
if(cm && cm.name == 'XLDAPR') p.D = true;
|
||||
}
|
||||
if(dense) {
|
||||
var _r = decode_cell(tag.r);
|
||||
if(!s[_r.r]) s[_r.r] = [];
|
||||
|
|
|
@ -538,6 +538,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
|
||||
XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
|
||||
|
||||
var cm, vm;
|
||||
|
||||
recordhopper(data, function ws_parse(val, R_n, RT) {
|
||||
if(end) return;
|
||||
switch(RT) {
|
||||
|
@ -595,6 +597,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
}
|
||||
if(!af && val.length > 3) p.f = val[3];
|
||||
}
|
||||
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
|
@ -602,12 +605,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
|
||||
var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
|
||||
}
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x0001: /* 'BrtCellBlank' */
|
||||
case 0x000C: /* 'BrtShortBlank' */
|
||||
if(!opts.sheetStubs || pass) break;
|
||||
p = ({t:'z',v:undefined}/*:any*/);
|
||||
p = ({t:'z',v:void 0}/*:any*/);
|
||||
C = val[0].c == -1 ? C + 1 : val[0].c;
|
||||
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
|
||||
else s[encode_col(C) + rr] = p;
|
||||
|
@ -615,11 +623,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
if(refguess.e.c < C) refguess.e.c = C;
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x00B0: /* 'BrtMergeCell' */
|
||||
merges.push(val); break;
|
||||
|
||||
case 0x0031: { /* 'BrtCellMeta' */
|
||||
cm = ((opts.xlmeta||{}).Types||[])[val-1];
|
||||
} break;
|
||||
|
||||
case 0x01EE: /* 'BrtHLink' */
|
||||
var rel = rels['!id'][val.relId];
|
||||
if(rel) {
|
||||
|
@ -707,7 +724,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
case 0x041A: /* 'BrtCFVO14' */
|
||||
case 0x0289: /* 'BrtCellIgnoreEC' */
|
||||
case 0x0451: /* 'BrtCellIgnoreEC14' */
|
||||
case 0x0031: /* 'BrtCellMeta' */
|
||||
case 0x024D: /* 'BrtCellSmartTagProperty' */
|
||||
case 0x025F: /* 'BrtCellWatch' */
|
||||
case 0x0234: /* 'BrtColor' */
|
||||
|
|
|
@ -52,6 +52,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) {
|
|||
return parse_xlink_xml((data/*:any*/), rel, name, opts);
|
||||
}
|
||||
|
||||
function parse_xlmeta(data, name/*:string*/, opts) {
|
||||
if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts);
|
||||
return parse_xlmeta_xml((data/*:any*/), name, opts);
|
||||
}
|
||||
|
||||
function write_wb(wb, name/*:string*/, opts) {
|
||||
return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
|
||||
}
|
||||
|
@ -81,3 +86,7 @@ function write_cc(data, name:string, opts) {
|
|||
return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
|
||||
}
|
||||
*/
|
||||
|
||||
function write_xlmeta(name/*:string*/) {
|
||||
return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
|
||||
/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
|
||||
/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
|
||||
/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
|
||||
/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE },
|
||||
/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
|
||||
/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
|
||||
/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
|
||||
|
@ -274,7 +274,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
|
||||
/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
|
||||
/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
|
||||
/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
|
||||
/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
|
||||
/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
|
||||
/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
|
||||
/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
|
||||
|
@ -795,7 +795,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
|
||||
/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
|
||||
/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
|
||||
/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
|
||||
/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" },
|
||||
/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
|
||||
/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
|
||||
/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
|
||||
|
@ -835,9 +835,27 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
|
||||
/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
|
||||
/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
|
||||
/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" },
|
||||
/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" },
|
||||
/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" },
|
||||
/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" },
|
||||
/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" },
|
||||
/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" },
|
||||
/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" },
|
||||
/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" },
|
||||
/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" },
|
||||
/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" },
|
||||
/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" },
|
||||
/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" },
|
||||
/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" },
|
||||
/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" },
|
||||
/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" },
|
||||
/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" },
|
||||
/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" },
|
||||
/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" },
|
||||
/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" },
|
||||
/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" },
|
||||
/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" },
|
||||
/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" },
|
||||
/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" },
|
||||
/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" },
|
||||
/*::[*/0xFFFF/*::]*/: { n:"" }
|
||||
};
|
||||
|
||||
|
|
|
@ -161,9 +161,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
|||
var wbrelsi = dir.workbooks[0].lastIndexOf("/");
|
||||
var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
|
||||
if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
|
||||
|
||||
if((dir.metadata || []).length >= 1) {
|
||||
/* TODO: MDX and other types of metadata */
|
||||
opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
|
||||
}
|
||||
|
||||
if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
|
||||
|
||||
|
||||
/* Numbers iOS hack */
|
||||
var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
|
||||
wsloop: for(i = 0; i != props.Worksheets; ++i) {
|
||||
|
|
|
@ -124,6 +124,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta(f));
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -132,7 +137,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
return zip;
|
||||
}
|
||||
|
||||
|
||||
/* this version does not reference XLSB write functions */
|
||||
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
_shapeid = 1024;
|
||||
if(wb && !wb.SSF) {
|
||||
|
@ -254,6 +259,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta_xml());
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
|
|
@ -45,14 +45,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
|
|||
}
|
||||
function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ {
|
||||
var oopts = {};
|
||||
var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
|
||||
if(o.compression) oopts.compression = 'DEFLATE';
|
||||
if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
|
||||
if(o.password) oopts.type = ftype;
|
||||
else switch(o.type) {
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
case "buffer":
|
||||
case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
|
||||
case "file": oopts.type = ftype; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
|
||||
|
|
|
@ -98,7 +98,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri
|
|||
};
|
||||
|
||||
/* set array formula and flush related cells */
|
||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
|
||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) {
|
||||
var rng = typeof range != "string" ? range : safe_decode_range(range);
|
||||
var rngstr = typeof range == "string" ? range : encode_range(range);
|
||||
for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
|
||||
|
@ -106,7 +106,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
|
|||
cell.t = 'n';
|
||||
cell.F = rngstr;
|
||||
delete cell.v;
|
||||
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
|
||||
if(R == rng.s.r && C == rng.s.c) {
|
||||
cell.f = formula;
|
||||
if(dynamic) cell.D = true;
|
||||
}
|
||||
}
|
||||
return ws;
|
||||
};
|
||||
|
|
|
@ -169,8 +169,8 @@ curl -X GET http://localhost:7262/?f=sheetjs.xlsb
|
|||
|
||||
[NestJS](https://nestjs.com/) is a Node.js framework for server-side web applications.
|
||||
|
||||
This demo uses SheetJS to injest a spreadsheet via a POST API endpoint. The file
|
||||
arrive to the endpoint as body `form-data`, accessible using the `file` key.
|
||||
This demo uses SheetJS to parse a spreadsheet via a POST API endpoint. The file
|
||||
arrives to the endpoint as body `form-data`, accessible using the `file` key.
|
||||
After parsing the file, CSV contents of the first worksheet will be returned.
|
||||
[Body parsing uses `multer`](https://docs.nestjs.com/techniques/file-upload).
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -160,7 +160,7 @@ var DO_NOT_EXPORT_CODEPAGE = true;
|
|||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
|
||||
var XLSX = {};
|
||||
function make_xlsx_lib(XLSX){
|
||||
XLSX.version = '0.18.2';
|
||||
XLSX.version = '0.18.3';
|
||||
var current_codepage = 1200, current_ansi = 1252;
|
||||
/*global cptable:true, window */
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
|
@ -288,7 +288,7 @@ var Base64 = function() {
|
|||
}
|
||||
};
|
||||
}();
|
||||
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node);
|
||||
var has_buf = (typeof Buffer !== 'undefined' && typeof undefined !== 'undefined' && typeof ({}) !== 'undefined' && !!({}).node);
|
||||
|
||||
var Buffer_from = function(){};
|
||||
|
||||
|
@ -1640,7 +1640,7 @@ function parse_extra_field(blob) {
|
|||
return o;
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function get_fs() { return fs || (fs = undefined); }
|
||||
function parse(file, options) {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options);
|
||||
|
@ -3256,7 +3256,7 @@ return exports;
|
|||
|
||||
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
|
||||
var _fs;
|
||||
if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
|
||||
if(typeof require !== 'undefined') try { _fs = undefined; } catch(e) {}
|
||||
|
||||
/* normalize data for blob ctor */
|
||||
function blobify(data) {
|
||||
|
@ -3270,7 +3270,7 @@ function write_dl(fname, payload, enc) {
|
|||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
if(typeof Deno !== 'undefined') {
|
||||
/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
|
||||
if(enc) switch(enc) {
|
||||
if(enc && typeof payload == "string") switch(enc) {
|
||||
case "utf8": payload = new TextEncoder(enc).encode(payload); break;
|
||||
case "binary": payload = s2ab(payload); break;
|
||||
/* TODO: binary equivalent */
|
||||
|
@ -4213,43 +4213,6 @@ function encode_range_xls(r, opts) {
|
|||
}
|
||||
return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
|
||||
}
|
||||
var OFFCRYPTO = {};
|
||||
|
||||
var make_offcrypto = function(O, _crypto) {
|
||||
var crypto;
|
||||
if(typeof _crypto !== 'undefined') crypto = _crypto;
|
||||
else if(typeof require !== 'undefined') {
|
||||
try { crypto = undefined; }
|
||||
catch(e) { crypto = null; }
|
||||
}
|
||||
|
||||
O.rc4 = function(key, data) {
|
||||
var S = new Array(256);
|
||||
var c = 0, i = 0, j = 0, t = 0;
|
||||
for(i = 0; i != 256; ++i) S[i] = i;
|
||||
for(i = 0; i != 256; ++i) {
|
||||
j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
|
||||
t = S[i]; S[i] = S[j]; S[j] = t;
|
||||
}
|
||||
// $FlowIgnore
|
||||
i = j = 0; var out = new_raw_buf(data.length);
|
||||
for(c = 0; c != data.length; ++c) {
|
||||
i = (i + 1)&255;
|
||||
j = (j + S[i])%256;
|
||||
t = S[i]; S[i] = S[j]; S[j] = t;
|
||||
out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
O.md5 = function(hex) {
|
||||
if(!crypto) throw new Error("Unsupported crypto");
|
||||
return crypto.createHash('md5').update(hex).digest('hex');
|
||||
};
|
||||
};
|
||||
/*global crypto:true */
|
||||
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
|
||||
|
||||
function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
|
||||
function encode_row(row) { return "" + (row + 1); }
|
||||
function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
|
||||
|
@ -4414,6 +4377,9 @@ function sheet_add_aoa(_ws, data, opts) {
|
|||
}
|
||||
function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
|
||||
|
||||
function parse_Int32LE(data) {
|
||||
return data.read_shift(4, 'i');
|
||||
}
|
||||
function write_UInt32LE(x, o) {
|
||||
if (!o) o = new_buf(4);
|
||||
o.write_shift(4, x);
|
||||
|
@ -5079,8 +5045,8 @@ var ct2type/*{[string]:string}*/ = ({
|
|||
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
|
||||
|
||||
/* Metadata */
|
||||
"application/vnd.ms-excel.sheetMetadata": "TODO",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
|
||||
"application/vnd.ms-excel.sheetMetadata": "metadata",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
|
||||
|
||||
/* PivotCache */
|
||||
"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
|
||||
|
@ -5197,6 +5163,10 @@ var CT_LIST = (function(){
|
|||
xlsx: "application/vnd.ms-excel.macrosheet+xml",
|
||||
xlsb: "application/vnd.ms-excel.macrosheet"
|
||||
},
|
||||
metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
|
||||
xlsb: "application/vnd.ms-excel.sheetMetadata"
|
||||
},
|
||||
styles: { /* Styles */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
||||
xlsb: "application/vnd.ms-excel.styles"
|
||||
|
@ -5216,7 +5186,7 @@ function new_ct() {
|
|||
workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
|
||||
rels:[], strs:[], comments:[], links:[],
|
||||
coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
|
||||
calcchains:[], vba: [], drawings: [],
|
||||
calcchains:[], vba: [], drawings: [], metadata: [],
|
||||
TODO:[], xmlns: "" });
|
||||
}
|
||||
|
||||
|
@ -5315,6 +5285,7 @@ function write_ct(ct, opts) {
|
|||
f3('vba');
|
||||
f3('comments');
|
||||
f3('drawings');
|
||||
f2('metadata');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -5381,7 +5352,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
|
|||
function add_rels(rels, rId, f, type, relobj, targetmode) {
|
||||
if(!relobj) relobj = {};
|
||||
if(!rels['!id']) rels['!id'] = {};
|
||||
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
if(!rels['!idx']) rels['!idx'] = 1;
|
||||
if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
rels['!idx'] = rId + 1;
|
||||
relobj.Id = 'rId' + rId;
|
||||
relobj.Type = type;
|
||||
relobj.Target = f;
|
||||
|
@ -11365,6 +11338,157 @@ function update_xfext(xf, xfext) {
|
|||
});
|
||||
}
|
||||
|
||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
||||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
||||
/* 18.6 Calculation Chain */
|
||||
function parse_cc_xml(data) {
|
||||
var d = [];
|
||||
|
@ -12690,7 +12814,7 @@ ixti = f[1][1]; r = f[1][2];
|
|||
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
|
||||
var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
|
||||
/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
|
||||
if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
|
||||
if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
|
||||
stack.push(name);
|
||||
break;
|
||||
|
||||
|
@ -14588,6 +14712,7 @@ function write_ws_xml_cell(cell, ref, ws, opts) {
|
|||
}
|
||||
if(cell.l) ws['!links'].push([ref, cell.l]);
|
||||
if(cell.c) ws['!comments'].push([ref, cell.c]);
|
||||
if(cell.D) o.cm = 1;
|
||||
return writextag('c', v, o);
|
||||
}
|
||||
|
||||
|
@ -14764,6 +14889,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
|
|||
}
|
||||
safe_format(p, fmtid, fillid, opts, themes, styles);
|
||||
if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
|
||||
if(tag.cm && opts.xlmeta) {
|
||||
var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
|
||||
if(cm && cm.name == 'XLDAPR') p.D = true;
|
||||
}
|
||||
if(dense) {
|
||||
var _r = decode_cell(tag.r);
|
||||
if(!s[_r.r]) s[_r.r] = [];
|
||||
|
@ -14846,7 +14975,7 @@ function write_ws_xml(idx, opts, wb, rels) {
|
|||
|
||||
o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
|
||||
|
||||
/* TODO: store in WB, process styles */
|
||||
/* TODO: store in WB, undefined styles */
|
||||
if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
|
||||
defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
|
||||
baseColWidth:opts.sheetFormat.baseColWidth||'10',
|
||||
|
@ -15477,6 +15606,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
|
||||
XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
|
||||
|
||||
var cm, vm;
|
||||
|
||||
recordhopper(data, function ws_parse(val, R_n, RT) {
|
||||
if(end) return;
|
||||
switch(RT) {
|
||||
|
@ -15534,6 +15665,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
}
|
||||
if(!af && val.length > 3) p.f = val[3];
|
||||
}
|
||||
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
|
@ -15541,12 +15673,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
|
||||
var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
|
||||
}
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x0001: /* 'BrtCellBlank' */
|
||||
case 0x000C: /* 'BrtShortBlank' */
|
||||
if(!opts.sheetStubs || pass) break;
|
||||
p = ({t:'z',v:undefined});
|
||||
p = ({t:'z',v:void 0});
|
||||
C = val[0].c == -1 ? C + 1 : val[0].c;
|
||||
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
|
||||
else s[encode_col(C) + rr] = p;
|
||||
|
@ -15554,11 +15691,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
if(refguess.e.c < C) refguess.e.c = C;
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x00B0: /* 'BrtMergeCell' */
|
||||
merges.push(val); break;
|
||||
|
||||
case 0x0031: { /* 'BrtCellMeta' */
|
||||
cm = ((opts.xlmeta||{}).Types||[])[val-1];
|
||||
} break;
|
||||
|
||||
case 0x01EE: /* 'BrtHLink' */
|
||||
var rel = rels['!id'][val.relId];
|
||||
if(rel) {
|
||||
|
@ -15646,7 +15792,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
case 0x041A: /* 'BrtCFVO14' */
|
||||
case 0x0289: /* 'BrtCellIgnoreEC' */
|
||||
case 0x0451: /* 'BrtCellIgnoreEC14' */
|
||||
case 0x0031: /* 'BrtCellMeta' */
|
||||
case 0x024D: /* 'BrtCellSmartTagProperty' */
|
||||
case 0x025F: /* 'BrtCellWatch' */
|
||||
case 0x0234: /* 'BrtColor' */
|
||||
|
@ -16851,6 +16996,11 @@ function parse_xlink(data, rel, name, opts) {
|
|||
return parse_xlink_xml((data), rel, name, opts);
|
||||
}
|
||||
|
||||
function parse_xlmeta(data, name, opts) {
|
||||
if(name.slice(-4)===".bin") return parse_xlmeta_bin((data), name, opts);
|
||||
return parse_xlmeta_xml((data), name, opts);
|
||||
}
|
||||
|
||||
function write_wb(wb, name, opts) {
|
||||
return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
|
||||
}
|
||||
|
@ -16880,6 +17030,10 @@ function write_cc(data, name:string, opts) {
|
|||
return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
|
||||
}
|
||||
*/
|
||||
|
||||
function write_xlmeta(name) {
|
||||
return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
|
||||
}
|
||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
|
||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
|
||||
function xlml_parsexmltag(tag, skip_root) {
|
||||
|
@ -18294,7 +18448,7 @@ function parse_workbook(blob, options) {
|
|||
var last_Rn = '';
|
||||
var file_depth = 0; /* TODO: make a real stack */
|
||||
var BIFF2Fmt = 0, BIFF2FmtTable = [];
|
||||
var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
|
||||
var FilterDatabases = []; /* TODO: sort out supbooks and undefined elsewhere */
|
||||
var last_lbl;
|
||||
|
||||
/* explicit override for some broken writers */
|
||||
|
@ -19136,7 +19290,7 @@ var XLSBRecordEnum = {
|
|||
0x002E: { n:"BrtBorder", f:parse_BrtBorder },
|
||||
0x002F: { n:"BrtXF", f:parse_BrtXF },
|
||||
0x0030: { n:"BrtStyle" },
|
||||
0x0031: { n:"BrtCellMeta" },
|
||||
0x0031: { n:"BrtCellMeta", f:parse_Int32LE },
|
||||
0x0032: { n:"BrtValueMeta" },
|
||||
0x0033: { n:"BrtMdb" },
|
||||
0x0034: { n:"BrtBeginFmd" },
|
||||
|
@ -19362,7 +19516,7 @@ var XLSBRecordEnum = {
|
|||
0x014C: { n:"BrtBeginMetadata" },
|
||||
0x014D: { n:"BrtEndMetadata" },
|
||||
0x014E: { n:"BrtBeginEsmdtinfo" },
|
||||
0x014F: { n:"BrtMdtinfo" },
|
||||
0x014F: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
|
||||
0x0150: { n:"BrtEndEsmdtinfo" },
|
||||
0x0151: { n:"BrtBeginEsmdb" },
|
||||
0x0152: { n:"BrtEndEsmdb" },
|
||||
|
@ -19883,7 +20037,7 @@ var XLSBRecordEnum = {
|
|||
0x0835: { n:"BrtEndTimelineStyleElements" },
|
||||
0x0836: { n:"BrtDxf15" },
|
||||
0x0837: { n:"BrtBeginDxfs15" },
|
||||
0x0838: { n:"brtEndDxfs15" },
|
||||
0x0838: { n:"BrtEndDxfs15" },
|
||||
0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
|
||||
0x083A: { n:"BrtBeginItemUniqueNames" },
|
||||
0x083B: { n:"BrtEndItemUniqueNames" },
|
||||
|
@ -19923,9 +20077,27 @@ var XLSBRecordEnum = {
|
|||
0x085D: { n:"BrtModelTimeGroupingCalcCol" },
|
||||
0x0C00: { n:"BrtUid" },
|
||||
0x0C01: { n:"BrtRevisionPtr" },
|
||||
0x13e7: { n:"BrtBeginCalcFeatures" },
|
||||
0x13e8: { n:"BrtEndCalcFeatures" },
|
||||
0x13e9: { n:"BrtCalcFeature" },
|
||||
0x1000: { n:"BrtBeginDynamicArrayPr" },
|
||||
0x1001: { n:"BrtEndDynamicArrayPr" },
|
||||
0x138A: { n:"BrtBeginRichValueBlock" },
|
||||
0x138B: { n:"BrtEndRichValueBlock" },
|
||||
0x13D9: { n:"BrtBeginRichFilters" },
|
||||
0x13DA: { n:"BrtEndRichFilters" },
|
||||
0x13DB: { n:"BrtRichFilter" },
|
||||
0x13DC: { n:"BrtBeginRichFilterColumn" },
|
||||
0x13DD: { n:"BrtEndRichFilterColumn" },
|
||||
0x13DE: { n:"BrtBeginCustomRichFilters" },
|
||||
0x13DF: { n:"BrtEndCustomRichFilters" },
|
||||
0x13E0: { n:"BrtCustomRichFilter" },
|
||||
0x13E1: { n:"BrtTop10RichFilter" },
|
||||
0x13E2: { n:"BrtDynamicRichFilter" },
|
||||
0x13E4: { n:"BrtBeginRichSortCondition" },
|
||||
0x13E5: { n:"BrtEndRichSortCondition" },
|
||||
0x13E6: { n:"BrtRichFilterDateGroupItem" },
|
||||
0x13E7: { n:"BrtBeginCalcFeatures" },
|
||||
0x13E8: { n:"BrtEndCalcFeatures" },
|
||||
0x13E9: { n:"BrtCalcFeature" },
|
||||
0x13EB: { n:"BrtExternalLinksPr" },
|
||||
0xFFFF: { n:"" }
|
||||
};
|
||||
|
||||
|
@ -20992,7 +21164,7 @@ function sheet_add_dom(ws, table, _opts) {
|
|||
}
|
||||
if(o.z === undefined && z != null) o.z = z;
|
||||
/* The first link is used. Links are assumed to be fully specified.
|
||||
* TODO: The right way to process relative links is to make a new <a> */
|
||||
* TODO: The right way to undefined relative links is to make a new <a> */
|
||||
var l = "", Aelts = elt.getElementsByTagName("A");
|
||||
if(Aelts && Aelts.length) for(var Aelti = 0; Aelti < Aelts.length; ++Aelti) if(Aelts[Aelti].hasAttribute("href")) {
|
||||
l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break;
|
||||
|
@ -22778,9 +22950,16 @@ function parse_zip(zip, opts) {
|
|||
var wbrelsi = dir.workbooks[0].lastIndexOf("/");
|
||||
var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
|
||||
if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
|
||||
|
||||
if((dir.metadata || []).length >= 1) {
|
||||
/* TODO: MDX and other types of metadata */
|
||||
opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
|
||||
}
|
||||
|
||||
if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
|
||||
|
||||
|
||||
/* Numbers iOS hack */
|
||||
var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
|
||||
wsloop: for(i = 0; i != props.Worksheets; ++i) {
|
||||
|
@ -23013,6 +23192,11 @@ f = "docProps/app.xml";
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta(f));
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -23021,7 +23205,7 @@ f = "docProps/app.xml";
|
|||
return zip;
|
||||
}
|
||||
|
||||
|
||||
/* this version does not reference XLSB write functions */
|
||||
function write_zip_xlsx(wb, opts) {
|
||||
_shapeid = 1024;
|
||||
if(wb && !wb.SSF) {
|
||||
|
@ -23142,6 +23326,11 @@ f = "docProps/app.xml";
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta_xml());
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -23195,6 +23384,7 @@ function read_plaintext_raw(data, o) {
|
|||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
|
||||
o.type = "binary";
|
||||
return read_plaintext(str, o);
|
||||
}
|
||||
|
||||
|
@ -23313,14 +23503,15 @@ function write_zip_typeXLSX(wb, opts) {
|
|||
}
|
||||
function write_zip_denouement(z, o) {
|
||||
var oopts = {};
|
||||
var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
|
||||
if(o.compression) oopts.compression = 'DEFLATE';
|
||||
if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
|
||||
if(o.password) oopts.type = ftype;
|
||||
else switch(o.type) {
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
case "buffer":
|
||||
case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
|
||||
case "file": oopts.type = ftype; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
|
||||
|
@ -23838,7 +24029,7 @@ utils.cell_add_comment = function(cell, text, author) {
|
|||
};
|
||||
|
||||
/* set array formula and flush related cells */
|
||||
utils.sheet_set_array_formula = function(ws, range, formula) {
|
||||
utils.sheet_set_array_formula = function(ws, range, formula, dynamic) {
|
||||
var rng = typeof range != "string" ? range : safe_decode_range(range);
|
||||
var rngstr = typeof range == "string" ? range : encode_range(range);
|
||||
for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
|
||||
|
@ -23846,7 +24037,10 @@ utils.sheet_set_array_formula = function(ws, range, formula) {
|
|||
cell.t = 'n';
|
||||
cell.F = rngstr;
|
||||
delete cell.v;
|
||||
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
|
||||
if(R == rng.s.r && C == rng.s.c) {
|
||||
cell.f = formula;
|
||||
if(dynamic) cell.D = true;
|
||||
}
|
||||
}
|
||||
return ws;
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -24,9 +24,5 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
|
|||
|
||||
![circo graph of format support](formats.png)
|
||||
|
||||
<details><summary><b>Diagram Legend</b> (click to show)</summary>
|
||||
|
||||
![graph legend](legend.png)
|
||||
|
||||
</details>
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ The complete single-file version is generated at `dist/xlsx.full.min.js`
|
|||
|
||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
|
||||
- codepage library skipped (no support for XLS encodings)
|
||||
- XLSX compression option not currently available
|
||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
|
||||
- node stream utils removed
|
||||
|
||||
|
|
|
@ -48,6 +48,18 @@ and approaches for steps 1 and 5.
|
|||
|
||||
Utility functions help with step 3.
|
||||
|
||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
|
||||
solutions for common data import scenarios.
|
||||
|
||||
["Packaging and Releasing Data"](#packaging-and-releasing-data) describes
|
||||
solutions for common data export scenarios.
|
||||
|
||||
["Processing Data"](#packaging-and-releasing-data) describes solutions for
|
||||
common workbook processing and manipulation scenarios.
|
||||
|
||||
["Utility Functions"](#utility-functions) details utility functions for
|
||||
translating JSON Arrays and other common JS structures into worksheet objects.
|
||||
|
||||
### The Zen of SheetJS
|
||||
|
||||
_Data processing should fit in any workflow_
|
||||
|
@ -56,15 +68,6 @@ The library does not impose a separate lifecycle. It fits nicely in websites
|
|||
and apps built using any framework. The plain JS data objects play nice with
|
||||
Web Workers and future APIs.
|
||||
|
||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
|
||||
solutions for common data import scenarios.
|
||||
|
||||
["Writing Workbooks"](#writing-workbooks) describes solutions for common data
|
||||
export scenarios involving actual spreadsheet files.
|
||||
|
||||
["Utility Functions"](#utility-functions) details utility functions for
|
||||
translating JSON Arrays and other common JS structures into worksheet objects.
|
||||
|
||||
_JavaScript is a powerful language for data processing_
|
||||
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
|
||||
|
|
|
@ -40,3 +40,9 @@ The [`demos` directory](demos/) includes sample projects for:
|
|||
|
||||
Other examples are included in the [showcase](demos/showcase/).
|
||||
|
||||
<https://sheetjs.com/demos/modify.html> shows a complete example of reading,
|
||||
modifying, and writing files.
|
||||
|
||||
<https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line
|
||||
tool included with node installations, reading spreadsheet files and exporting
|
||||
the contents in various formats.
|
||||
|
|
|
@ -440,3 +440,4 @@ const workbook = XLSX.read(data);
|
|||
</details>
|
||||
|
||||
More detailed examples are covered in the [included demos](demos/)
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
### Processing JSON and JS Data
|
||||
|
||||
JSON and JS data tend to represent single worksheets. This section will use a
|
||||
few utility functions to generate workbooks:
|
||||
few utility functions to generate workbooks.
|
||||
|
||||
_Create a new Worksheet_
|
||||
_Create a new Workbook_
|
||||
|
||||
```js
|
||||
var workbook = XLSX.utils.book_new();
|
||||
|
@ -11,16 +11,9 @@ var workbook = XLSX.utils.book_new();
|
|||
|
||||
The `book_new` utility function creates an empty workbook with no worksheets.
|
||||
|
||||
|
||||
_Append a Worksheet to a Workbook_
|
||||
|
||||
```js
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
|
||||
```
|
||||
|
||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
|
||||
The third argument specifies the desired worksheet name. Multiple worksheets can
|
||||
be added to a workbook by calling the function multiple times.
|
||||
Spreadsheet software generally require at least one worksheet and enforce the
|
||||
requirement in the user interface. This library enforces the requirement at
|
||||
write time, throwing errors if an empty workbook is passed to write functions.
|
||||
|
||||
|
||||
**API**
|
||||
|
@ -33,14 +26,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
|
|||
|
||||
The `aoa_to_sheet` utility function walks an "array of arrays" in row-major
|
||||
order, generating a worksheet object. The following snippet generates a sheet
|
||||
with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc:
|
||||
with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
["A1", "B1", "C1"],
|
||||
["A2", "B2", "C2"],
|
||||
["A3", "B3", "C3"]
|
||||
])
|
||||
]);
|
||||
```
|
||||
|
||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
|
||||
|
|
|
@ -1,38 +1,54 @@
|
|||
## Working with the Workbook
|
||||
## Processing Data
|
||||
|
||||
The full object format is described later in this README.
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
|
||||
representation of the core concepts of a workbook. The utility functions work
|
||||
with the object representation and are intended to handle common use cases.
|
||||
|
||||
<details>
|
||||
<summary><b>Reading a specific cell </b> (click to show)</summary>
|
||||
### Modifying Workbook Structure
|
||||
|
||||
This example extracts the value stored in cell A1 from the first worksheet:
|
||||
**API**
|
||||
|
||||
_Append a Worksheet to a Workbook_
|
||||
|
||||
```js
|
||||
var first_sheet_name = workbook.SheetNames[0];
|
||||
var address_of_cell = 'A1';
|
||||
|
||||
/* Get worksheet */
|
||||
var worksheet = workbook.Sheets[first_sheet_name];
|
||||
|
||||
/* Find desired cell */
|
||||
var desired_cell = worksheet[address_of_cell];
|
||||
|
||||
/* Get the value */
|
||||
var desired_value = (desired_cell ? desired_cell.v : undefined);
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
|
||||
```
|
||||
|
||||
</details>
|
||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
|
||||
The third argument specifies the desired worksheet name. Multiple worksheets can
|
||||
be added to a workbook by calling the function multiple times.
|
||||
|
||||
_List the Worksheet names in tab order_
|
||||
|
||||
```js
|
||||
var wsnames = workbook.SheetNames;
|
||||
```
|
||||
|
||||
The `SheetNames` property of the workbook object is a list of the worksheet
|
||||
names in "tab order". API functions will look at this array.
|
||||
|
||||
_Replace a Worksheet in place_
|
||||
|
||||
```js
|
||||
workbook.Sheets[sheet_name] = new_worksheet;
|
||||
```
|
||||
|
||||
The `Sheets` property of the workbook object is an object whose keys are names
|
||||
and whose values are worksheet objects. By reassigning to a property of the
|
||||
`Sheets` object, the worksheet object can be changed without disrupting the
|
||||
rest of the worksheet structure.
|
||||
|
||||
**Examples**
|
||||
|
||||
<details>
|
||||
<summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary>
|
||||
<summary><b>Add a new worksheet to a workbook</b> (click to show)</summary>
|
||||
|
||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
|
||||
sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
|
||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input).
|
||||
|
||||
```js
|
||||
var ws_name = "SheetJS";
|
||||
|
||||
/* make worksheet */
|
||||
/* Create worksheet */
|
||||
var ws_data = [
|
||||
[ "S", "h", "e", "e", "t", "J", "S" ],
|
||||
[ 1 , 2 , 3 , 4 , 5 ]
|
||||
|
@ -45,39 +61,58 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name);
|
|||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Creating a new workbook from scratch</b> (click to show)</summary>
|
||||
### Modifying Cell Values
|
||||
|
||||
The workbook object contains a `SheetNames` array of names and a `Sheets` object
|
||||
mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
|
||||
creates a new workbook object:
|
||||
**API**
|
||||
|
||||
_Modify a single cell value in a worksheet_
|
||||
|
||||
```js
|
||||
/* create a new blank workbook */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address });
|
||||
```
|
||||
|
||||
The new workbook is blank and contains no worksheets. The write functions will
|
||||
error if the workbook is empty.
|
||||
_Modify multiple cell values in a worksheet_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, aoa, opts);
|
||||
```
|
||||
|
||||
The `sheet_add_aoa` utility function modifies cell values in a worksheet. The
|
||||
first argument is the worksheet object. The second argument is an array of
|
||||
arrays of values. The `origin` key of the third argument controls where cells
|
||||
will be written. The following snippet sets `B3=1` and `E5="abc"`:
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
[1], // <-- Write 1 to cell B3
|
||||
, // <-- Do nothing in row 4
|
||||
[/*B5*/, /*C5*/, /*D5*/, "abc"] // <-- Write "abc" to cell E5
|
||||
], { origin: "B3" });
|
||||
```
|
||||
|
||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
|
||||
optional `opts` argument in more detail.
|
||||
|
||||
**Examples**
|
||||
|
||||
<details>
|
||||
<summary><b>Appending rows to a worksheet</b> (click to show)</summary>
|
||||
|
||||
The special origin value `-1` instructs `sheet_add_aoa` to start in column A of
|
||||
the row after the last row in the range, appending the data:
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
["first row after data", 1],
|
||||
["second row after data", 2]
|
||||
], { origin: -1 });
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### Parsing and Writing Examples
|
||||
### Modifying Other Worksheet / Workbook / Cell Properties
|
||||
|
||||
- <https://sheetjs.com/demos/modify.html> read + modify + write files
|
||||
|
||||
- <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node
|
||||
|
||||
The node version installs a command line tool `xlsx` which can read spreadsheet
|
||||
files and output the contents in various formats. The source is available at
|
||||
`xlsx.njs` in the bin directory.
|
||||
|
||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
|
||||
|
||||
- `XLSX.utils.sheet_to_csv` generates CSV
|
||||
- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
|
||||
- `XLSX.utils.sheet_to_html` generates HTML
|
||||
- `XLSX.utils.sheet_to_json` generates an array of objects
|
||||
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes
|
||||
the object structures in greater detail.
|
||||
|
||||
|
|
|
@ -255,3 +255,42 @@ The [`vuejs` demo](demos/vue) includes more React examples.
|
|||
|
||||
</details>
|
||||
|
||||
### Generating Single-Worksheet Snapshots
|
||||
|
||||
The `sheet_to_*` functions accept a worksheet object.
|
||||
|
||||
**API**
|
||||
|
||||
_Generate a CSV from a single worksheet_
|
||||
|
||||
```js
|
||||
var csv = XLSX.utils.sheet_to_csv(worksheet, opts);
|
||||
```
|
||||
|
||||
This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type.
|
||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
|
||||
function and the optional `opts` argument in more detail.
|
||||
|
||||
_Generate "Text" from a single worksheet_
|
||||
|
||||
```js
|
||||
var txt = XLSX.utils.sheet_to_txt(worksheet, opts);
|
||||
```
|
||||
|
||||
This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type.
|
||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
|
||||
function and the optional `opts` argument in more detail.
|
||||
|
||||
_Generate a list of formulae from a single worksheet_
|
||||
|
||||
```js
|
||||
var fmla = XLSX.utils.sheet_to_formulae(worksheet);
|
||||
```
|
||||
|
||||
This snapshot generates an array of entries representing the embedded formulae.
|
||||
Array formulae are rendered in the form `range=formula` while plain cells are
|
||||
rendered in the form `cell=formula or value`. String literals are prefixed with
|
||||
an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
|
||||
["Formulae Output"](#formulae-output) describes the function in more detail.
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ Cell objects are plain JS objects with keys and values following the convention:
|
|||
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
|
||||
| `f` | cell formula encoded as an A1-style string (if applicable) |
|
||||
| `F` | range of enclosing array if formula is array formula (if applicable) |
|
||||
| `D` | if true, array formula is dynamic (if applicable) |
|
||||
| `r` | rich text encoding (if applicable) |
|
||||
| `h` | HTML rendering of the rich text (if applicable) |
|
||||
| `c` | comments associated with the cell |
|
||||
|
|
|
@ -6,79 +6,7 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
|
|||
do not start with `=`.
|
||||
|
||||
<details>
|
||||
<summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
{
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:1 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', v:3, f:'A1+A2' }
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
Shared formulae are decompressed and each cell has the formula corresponding to
|
||||
its cell. Writers generally do not attempt to generate shared formulae.
|
||||
|
||||
Cells with formula entries but no value will be serialized in a way that Excel
|
||||
and other spreadsheet tools will recognize. This library will not automatically
|
||||
compute formula results! For example, to compute `BESSELJ` in a worksheet:
|
||||
|
||||
<details>
|
||||
<summary><b>Formula without known value</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
{
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:3.14159 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', f:'BESSELJ(A1,A2)' }
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
**Array Formulae**
|
||||
|
||||
Array formulae are stored in the top-left cell of the array block. All cells
|
||||
of an array formula have a `F` field corresponding to the range. A single-cell
|
||||
formula can be distinguished from a plain formula by the presence of `F` field.
|
||||
|
||||
<details>
|
||||
<summary><b>Array Formula examples</b> (click to show)</summary>
|
||||
|
||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
|
||||
|
||||
```js
|
||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
|
||||
```
|
||||
|
||||
For a multi-cell array formula, every cell has the same array range but only the
|
||||
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
|
||||
|
||||
```js
|
||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
|
||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
|
||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Utilities and writers are expected to check for the presence of a `F` field and
|
||||
ignore any possible formula element `f` in cells other than the starting cell.
|
||||
They are not expected to perform validation of the formulae!
|
||||
|
||||
<details>
|
||||
<summary><b>Formula Output Utility Function</b> (click to show)</summary>
|
||||
|
||||
The `sheet_to_formulae` method generates one line per formula or array formula.
|
||||
Array formulae are rendered in the form `range=formula` while plain cells are
|
||||
rendered in the form `cell=formula or value`. Note that string literals are
|
||||
prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Formulae File Format Details</b> (click to show)</summary>
|
||||
<summary><b>Formulae File Format Support</b> (click to show)</summary>
|
||||
|
||||
| Storage Representation | Formats | Read | Write |
|
||||
|:-----------------------|:-------------------------|:-----:|:-----:|
|
||||
|
@ -92,5 +20,271 @@ Since Excel prohibits named cells from colliding with names of A1 or RC style
|
|||
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
|
||||
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
|
||||
formulae can be converted with regular expressions.
|
||||
|
||||
Shared formulae are decompressed and each cell has the formula corresponding to
|
||||
its cell. Writers generally do not attempt to generate shared formulae.
|
||||
</details>
|
||||
|
||||
**Single-Cell Formulae**
|
||||
|
||||
For simple formulae, the `f` key of the desired cell can be set to the actual
|
||||
formula text. This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
|
||||
|
||||
```js
|
||||
var worksheet = {
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:1 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', v:3, f:'A1+A2' }
|
||||
};
|
||||
```
|
||||
|
||||
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
[ 1 ], // A1
|
||||
[ 2 ], // A2
|
||||
[ {t: "n", v: 3, f: "A1+A2"} ] // A3
|
||||
]);
|
||||
```
|
||||
|
||||
Cells with formula entries but no value will be serialized in a way that Excel
|
||||
and other spreadsheet tools will recognize. This library will not automatically
|
||||
compute formula results! For example, the following worksheet will include the
|
||||
`BESSELJ` function but the result will not be available in JavaScript:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
[ 3.14159, 2 ], // Row "1"
|
||||
[ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
|
||||
}
|
||||
```
|
||||
|
||||
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
|
||||
offers a formula calculator component for evaluating expressions, updating
|
||||
values and dependent cells, and refreshing entire workbooks.
|
||||
|
||||
|
||||
**Array Formulae**
|
||||
|
||||
_Assign an array formula_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
|
||||
```
|
||||
|
||||
Array formulae are stored in the top-left cell of the array block. All cells
|
||||
of an array formula have a `F` field corresponding to the range. A single-cell
|
||||
formula can be distinguished from a plain formula by the presence of `F` field.
|
||||
|
||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
|
||||
```
|
||||
|
||||
For a multi-cell array formula, every cell has the same array range but only the
|
||||
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
|
||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
|
||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
|
||||
```
|
||||
|
||||
Utilities and writers are expected to check for the presence of a `F` field and
|
||||
ignore any possible formula element `f` in cells other than the starting cell.
|
||||
They are not expected to perform validation of the formulae!
|
||||
|
||||
|
||||
**Dynamic Array Formulae**
|
||||
|
||||
_Assign a dynamic array formula_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
|
||||
```
|
||||
|
||||
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
|
||||
file formats. They are represented like normal array formulae but have special
|
||||
cell metadata indicating that the formula should be allowed to adjust the range.
|
||||
|
||||
An array formula can be marked as dynamic by setting the cell's `D` property to
|
||||
true. The `F` range is expected but can be the set to the current cell:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
|
||||
```
|
||||
|
||||
**Localization with Function Names**
|
||||
|
||||
SheetJS operates at the file level. Excel stores formula expressions using the
|
||||
English (United States) function names. For non-English users, Excel uses a
|
||||
localized set of function names.
|
||||
|
||||
For example, when the computer language and region is set to French (France),
|
||||
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function. However,
|
||||
in the actual file, Excel stores `SUM(A1:C3)`.
|
||||
|
||||
**Prefixed "Future Functions"**
|
||||
|
||||
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
|
||||
stored in files. When writing formula expressions using these functions, the
|
||||
prefix is required for maximal compatibility:
|
||||
|
||||
```js
|
||||
// Broadest compatibility
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
|
||||
|
||||
// Can cause errors in spreadsheet software
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
|
||||
```
|
||||
|
||||
When reading a file, the `xlfn` option preserves the prefixes.
|
||||
|
||||
<details>
|
||||
<summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary>
|
||||
|
||||
This list is growing with each Excel release.
|
||||
|
||||
```
|
||||
ACOT
|
||||
ACOTH
|
||||
AGGREGATE
|
||||
ARABIC
|
||||
BASE
|
||||
BETA.DIST
|
||||
BETA.INV
|
||||
BINOM.DIST
|
||||
BINOM.DIST.RANGE
|
||||
BINOM.INV
|
||||
BITAND
|
||||
BITLSHIFT
|
||||
BITOR
|
||||
BITRSHIFT
|
||||
BITXOR
|
||||
BYCOL
|
||||
BYROW
|
||||
CEILING.MATH
|
||||
CEILING.PRECISE
|
||||
CHISQ.DIST
|
||||
CHISQ.DIST.RT
|
||||
CHISQ.INV
|
||||
CHISQ.INV.RT
|
||||
CHISQ.TEST
|
||||
COMBINA
|
||||
CONFIDENCE.NORM
|
||||
CONFIDENCE.T
|
||||
COT
|
||||
COTH
|
||||
COVARIANCE.P
|
||||
COVARIANCE.S
|
||||
CSC
|
||||
CSCH
|
||||
DAYS
|
||||
DECIMAL
|
||||
ERF.PRECISE
|
||||
ERFC.PRECISE
|
||||
EXPON.DIST
|
||||
F.DIST
|
||||
F.DIST.RT
|
||||
F.INV
|
||||
F.INV.RT
|
||||
F.TEST
|
||||
FIELDVALUE
|
||||
FILTERXML
|
||||
FLOOR.MATH
|
||||
FLOOR.PRECISE
|
||||
FORMULATEXT
|
||||
GAMMA
|
||||
GAMMA.DIST
|
||||
GAMMA.INV
|
||||
GAMMALN.PRECISE
|
||||
GAUSS
|
||||
HYPGEOM.DIST
|
||||
IFNA
|
||||
IMCOSH
|
||||
IMCOT
|
||||
IMCSC
|
||||
IMCSCH
|
||||
IMSEC
|
||||
IMSECH
|
||||
IMSINH
|
||||
IMTAN
|
||||
ISFORMULA
|
||||
ISOMITTED
|
||||
ISOWEEKNUM
|
||||
LAMBDA
|
||||
LET
|
||||
LOGNORM.DIST
|
||||
LOGNORM.INV
|
||||
MAKEARRAY
|
||||
MAP
|
||||
MODE.MULT
|
||||
MODE.SNGL
|
||||
MUNIT
|
||||
NEGBINOM.DIST
|
||||
NORM.DIST
|
||||
NORM.INV
|
||||
NORM.S.DIST
|
||||
NORM.S.INV
|
||||
NUMBERVALUE
|
||||
PDURATION
|
||||
PERCENTILE.EXC
|
||||
PERCENTILE.INC
|
||||
PERCENTRANK.EXC
|
||||
PERCENTRANK.INC
|
||||
PERMUTATIONA
|
||||
PHI
|
||||
POISSON.DIST
|
||||
QUARTILE.EXC
|
||||
QUARTILE.INC
|
||||
QUERYSTRING
|
||||
RANDARRAY
|
||||
RANK.AVG
|
||||
RANK.EQ
|
||||
REDUCE
|
||||
RRI
|
||||
SCAN
|
||||
SEC
|
||||
SECH
|
||||
SEQUENCE
|
||||
SHEET
|
||||
SHEETS
|
||||
SKEW.P
|
||||
SORTBY
|
||||
STDEV.P
|
||||
STDEV.S
|
||||
T.DIST
|
||||
T.DIST.2T
|
||||
T.DIST.RT
|
||||
T.INV
|
||||
T.INV.2T
|
||||
T.TEST
|
||||
UNICHAR
|
||||
UNICODE
|
||||
UNIQUE
|
||||
VAR.P
|
||||
VAR.S
|
||||
WEBSERVICE
|
||||
WEIBULL.DIST
|
||||
XLOOKUP
|
||||
XOR
|
||||
Z.TEST
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
|
1
mini.lst
1
mini.lst
|
@ -28,6 +28,7 @@ bits/42_sstxml.js
|
|||
bits/46_stycommon.js
|
||||
bits/47_styxml.js
|
||||
bits/49_theme.js
|
||||
misc/51_xlsxmeta.js
|
||||
bits/53_externlink.js
|
||||
bits/54_drawing.js
|
||||
bits/55_vml.js
|
||||
|
|
|
@ -14,7 +14,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
|||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
if(typeof Deno !== 'undefined') {
|
||||
/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
|
||||
if(enc) switch(enc) {
|
||||
if(enc && typeof payload == "string") switch(enc) {
|
||||
case "utf8": payload = new TextEncoder(enc).encode(payload); break;
|
||||
case "binary": payload = s2ab(payload); break;
|
||||
/* TODO: binary equivalent */
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
|
@ -24,10 +24,8 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
|
|||
|
||||
![circo graph of format support](formats.png)
|
||||
|
||||
|
||||
![graph legend](legend.png)
|
||||
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
|
@ -42,14 +40,17 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
|
|||
* [Parsing Workbooks](#parsing-workbooks)
|
||||
* [Processing JSON and JS Data](#processing-json-and-js-data)
|
||||
* [Processing HTML Tables](#processing-html-tables)
|
||||
- [Working with the Workbook](#working-with-the-workbook)
|
||||
* [Parsing and Writing Examples](#parsing-and-writing-examples)
|
||||
- [Processing Data](#processing-data)
|
||||
* [Modifying Workbook Structure](#modifying-workbook-structure)
|
||||
* [Modifying Cell Values](#modifying-cell-values)
|
||||
* [Modifying Other Worksheet / Workbook / Cell Properties](#modifying-other-worksheet--workbook--cell-properties)
|
||||
- [Packaging and Releasing Data](#packaging-and-releasing-data)
|
||||
* [Writing Workbooks](#writing-workbooks)
|
||||
* [Writing Examples](#writing-examples)
|
||||
* [Streaming Write](#streaming-write)
|
||||
* [Generating JSON and JS Data](#generating-json-and-js-data)
|
||||
* [Generating HTML Tables](#generating-html-tables)
|
||||
* [Generating Single-Worksheet Snapshots](#generating-single-worksheet-snapshots)
|
||||
- [Interface](#interface)
|
||||
* [Parsing functions](#parsing-functions)
|
||||
* [Writing functions](#writing-functions)
|
||||
|
@ -140,10 +141,11 @@ For example, `unpkg` makes the latest version available at:
|
|||
|
||||
The complete single-file version is generated at `dist/xlsx.full.min.js`
|
||||
|
||||
`dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings)
|
||||
|
||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
|
||||
- codepage library skipped (no support for XLS encodings)
|
||||
- XLSX compression option not currently available
|
||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003
|
||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
|
||||
- node stream utils removed
|
||||
|
||||
|
||||
|
@ -303,6 +305,18 @@ and approaches for steps 1 and 5.
|
|||
|
||||
Utility functions help with step 3.
|
||||
|
||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
|
||||
solutions for common data import scenarios.
|
||||
|
||||
["Packaging and Releasing Data"](#packaging-and-releasing-data) describes
|
||||
solutions for common data export scenarios.
|
||||
|
||||
["Processing Data"](#packaging-and-releasing-data) describes solutions for
|
||||
common workbook processing and manipulation scenarios.
|
||||
|
||||
["Utility Functions"](#utility-functions) details utility functions for
|
||||
translating JSON Arrays and other common JS structures into worksheet objects.
|
||||
|
||||
### The Zen of SheetJS
|
||||
|
||||
_Data processing should fit in any workflow_
|
||||
|
@ -311,15 +325,6 @@ The library does not impose a separate lifecycle. It fits nicely in websites
|
|||
and apps built using any framework. The plain JS data objects play nice with
|
||||
Web Workers and future APIs.
|
||||
|
||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
|
||||
solutions for common data import scenarios.
|
||||
|
||||
["Writing Workbooks"](#writing-workbooks) describes solutions for common data
|
||||
export scenarios involving actual spreadsheet files.
|
||||
|
||||
["Utility Functions"](#utility-functions) details utility functions for
|
||||
translating JSON Arrays and other common JS structures into worksheet objects.
|
||||
|
||||
_JavaScript is a powerful language for data processing_
|
||||
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
|
||||
|
@ -559,6 +564,12 @@ The [`demos` directory](demos/) includes sample projects for:
|
|||
|
||||
Other examples are included in the [showcase](demos/showcase/).
|
||||
|
||||
<https://sheetjs.com/demos/modify.html> shows a complete example of reading,
|
||||
modifying, and writing files.
|
||||
|
||||
<https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line
|
||||
tool included with node installations, reading spreadsheet files and exporting
|
||||
the contents in various formats.
|
||||
## Acquiring and Extracting Data
|
||||
|
||||
### Parsing Workbooks
|
||||
|
@ -962,12 +973,13 @@ const workbook = XLSX.read(data);
|
|||
|
||||
|
||||
More detailed examples are covered in the [included demos](demos/)
|
||||
|
||||
### Processing JSON and JS Data
|
||||
|
||||
JSON and JS data tend to represent single worksheets. This section will use a
|
||||
few utility functions to generate workbooks:
|
||||
few utility functions to generate workbooks.
|
||||
|
||||
_Create a new Worksheet_
|
||||
_Create a new Workbook_
|
||||
|
||||
```js
|
||||
var workbook = XLSX.utils.book_new();
|
||||
|
@ -975,16 +987,9 @@ var workbook = XLSX.utils.book_new();
|
|||
|
||||
The `book_new` utility function creates an empty workbook with no worksheets.
|
||||
|
||||
|
||||
_Append a Worksheet to a Workbook_
|
||||
|
||||
```js
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
|
||||
```
|
||||
|
||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
|
||||
The third argument specifies the desired worksheet name. Multiple worksheets can
|
||||
be added to a workbook by calling the function multiple times.
|
||||
Spreadsheet software generally require at least one worksheet and enforce the
|
||||
requirement in the user interface. This library enforces the requirement at
|
||||
write time, throwing errors if an empty workbook is passed to write functions.
|
||||
|
||||
|
||||
**API**
|
||||
|
@ -997,14 +1002,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
|
|||
|
||||
The `aoa_to_sheet` utility function walks an "array of arrays" in row-major
|
||||
order, generating a worksheet object. The following snippet generates a sheet
|
||||
with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc:
|
||||
with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
["A1", "B1", "C1"],
|
||||
["A2", "B2", "C2"],
|
||||
["A3", "B3", "C3"]
|
||||
])
|
||||
]);
|
||||
```
|
||||
|
||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
|
||||
|
@ -1284,36 +1289,55 @@ const workbook = XLSX.utils.table_to_book(doc);
|
|||
```
|
||||
|
||||
|
||||
## Working with the Workbook
|
||||
## Processing Data
|
||||
|
||||
The full object format is described later in this README.
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
|
||||
representation of the core concepts of a workbook. The utility functions work
|
||||
with the object representation and are intended to handle common use cases.
|
||||
|
||||
### Modifying Workbook Structure
|
||||
|
||||
This example extracts the value stored in cell A1 from the first worksheet:
|
||||
**API**
|
||||
|
||||
_Append a Worksheet to a Workbook_
|
||||
|
||||
```js
|
||||
var first_sheet_name = workbook.SheetNames[0];
|
||||
var address_of_cell = 'A1';
|
||||
|
||||
/* Get worksheet */
|
||||
var worksheet = workbook.Sheets[first_sheet_name];
|
||||
|
||||
/* Find desired cell */
|
||||
var desired_cell = worksheet[address_of_cell];
|
||||
|
||||
/* Get the value */
|
||||
var desired_value = (desired_cell ? desired_cell.v : undefined);
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
|
||||
```
|
||||
|
||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
|
||||
The third argument specifies the desired worksheet name. Multiple worksheets can
|
||||
be added to a workbook by calling the function multiple times.
|
||||
|
||||
_List the Worksheet names in tab order_
|
||||
|
||||
```js
|
||||
var wsnames = workbook.SheetNames;
|
||||
```
|
||||
|
||||
The `SheetNames` property of the workbook object is a list of the worksheet
|
||||
names in "tab order". API functions will look at this array.
|
||||
|
||||
_Replace a Worksheet in place_
|
||||
|
||||
```js
|
||||
workbook.Sheets[sheet_name] = new_worksheet;
|
||||
```
|
||||
|
||||
The `Sheets` property of the workbook object is an object whose keys are names
|
||||
and whose values are worksheet objects. By reassigning to a property of the
|
||||
`Sheets` object, the worksheet object can be changed without disrupting the
|
||||
rest of the worksheet structure.
|
||||
|
||||
**Examples**
|
||||
|
||||
|
||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
|
||||
sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
|
||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input).
|
||||
|
||||
```js
|
||||
var ws_name = "SheetJS";
|
||||
|
||||
/* make worksheet */
|
||||
/* Create worksheet */
|
||||
var ws_data = [
|
||||
[ "S", "h", "e", "e", "t", "J", "S" ],
|
||||
[ 1 , 2 , 3 , 4 , 5 ]
|
||||
|
@ -1325,38 +1349,57 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name);
|
|||
```
|
||||
|
||||
|
||||
### Modifying Cell Values
|
||||
|
||||
The workbook object contains a `SheetNames` array of names and a `Sheets` object
|
||||
mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
|
||||
creates a new workbook object:
|
||||
**API**
|
||||
|
||||
_Modify a single cell value in a worksheet_
|
||||
|
||||
```js
|
||||
/* create a new blank workbook */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address });
|
||||
```
|
||||
|
||||
The new workbook is blank and contains no worksheets. The write functions will
|
||||
error if the workbook is empty.
|
||||
_Modify multiple cell values in a worksheet_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, aoa, opts);
|
||||
```
|
||||
|
||||
The `sheet_add_aoa` utility function modifies cell values in a worksheet. The
|
||||
first argument is the worksheet object. The second argument is an array of
|
||||
arrays of values. The `origin` key of the third argument controls where cells
|
||||
will be written. The following snippet sets `B3=1` and `E5="abc"`:
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
[1], // <-- Write 1 to cell B3
|
||||
, // <-- Do nothing in row 4
|
||||
[/*B5*/, /*C5*/, /*D5*/, "abc"] // <-- Write "abc" to cell E5
|
||||
], { origin: "B3" });
|
||||
```
|
||||
|
||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
|
||||
optional `opts` argument in more detail.
|
||||
|
||||
**Examples**
|
||||
|
||||
|
||||
The special origin value `-1` instructs `sheet_add_aoa` to start in column A of
|
||||
the row after the last row in the range, appending the data:
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [
|
||||
["first row after data", 1],
|
||||
["second row after data", 2]
|
||||
], { origin: -1 });
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Parsing and Writing Examples
|
||||
### Modifying Other Worksheet / Workbook / Cell Properties
|
||||
|
||||
- <https://sheetjs.com/demos/modify.html> read + modify + write files
|
||||
|
||||
- <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node
|
||||
|
||||
The node version installs a command line tool `xlsx` which can read spreadsheet
|
||||
files and output the contents in various formats. The source is available at
|
||||
`xlsx.njs` in the bin directory.
|
||||
|
||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
|
||||
|
||||
- `XLSX.utils.sheet_to_csv` generates CSV
|
||||
- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
|
||||
- `XLSX.utils.sheet_to_html` generates HTML
|
||||
- `XLSX.utils.sheet_to_json` generates an array of objects
|
||||
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
|
||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes
|
||||
the object structures in greater detail.
|
||||
|
||||
## Packaging and Releasing Data
|
||||
|
||||
|
@ -1832,6 +1875,45 @@ const S5SComponent = {
|
|||
The [`vuejs` demo](demos/vue) includes more React examples.
|
||||
|
||||
|
||||
### Generating Single-Worksheet Snapshots
|
||||
|
||||
The `sheet_to_*` functions accept a worksheet object.
|
||||
|
||||
**API**
|
||||
|
||||
_Generate a CSV from a single worksheet_
|
||||
|
||||
```js
|
||||
var csv = XLSX.utils.sheet_to_csv(worksheet, opts);
|
||||
```
|
||||
|
||||
This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type.
|
||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
|
||||
function and the optional `opts` argument in more detail.
|
||||
|
||||
_Generate "Text" from a single worksheet_
|
||||
|
||||
```js
|
||||
var txt = XLSX.utils.sheet_to_txt(worksheet, opts);
|
||||
```
|
||||
|
||||
This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type.
|
||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
|
||||
function and the optional `opts` argument in more detail.
|
||||
|
||||
_Generate a list of formulae from a single worksheet_
|
||||
|
||||
```js
|
||||
var fmla = XLSX.utils.sheet_to_formulae(worksheet);
|
||||
```
|
||||
|
||||
This snapshot generates an array of entries representing the embedded formulae.
|
||||
Array formulae are rendered in the form `range=formula` while plain cells are
|
||||
rendered in the form `cell=formula or value`. String literals are prefixed with
|
||||
an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
|
||||
["Formulae Output"](#formulae-output) describes the function in more detail.
|
||||
|
||||
## Interface
|
||||
|
||||
`XLSX` is the exposed variable in the browser and the exported node variable
|
||||
|
@ -1934,6 +2016,7 @@ Cell objects are plain JS objects with keys and values following the convention:
|
|||
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
|
||||
| `f` | cell formula encoded as an A1-style string (if applicable) |
|
||||
| `F` | range of enclosing array if formula is array formula (if applicable) |
|
||||
| `D` | if true, array formula is dynamic (if applicable) |
|
||||
| `r` | rich text encoding (if applicable) |
|
||||
| `h` | HTML rendering of the rich text (if applicable) |
|
||||
| `c` | comments associated with the cell |
|
||||
|
@ -2261,66 +2344,6 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
|
|||
do not start with `=`.
|
||||
|
||||
|
||||
```js
|
||||
{
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:1 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', v:3, f:'A1+A2' }
|
||||
}
|
||||
```
|
||||
|
||||
Shared formulae are decompressed and each cell has the formula corresponding to
|
||||
its cell. Writers generally do not attempt to generate shared formulae.
|
||||
|
||||
Cells with formula entries but no value will be serialized in a way that Excel
|
||||
and other spreadsheet tools will recognize. This library will not automatically
|
||||
compute formula results! For example, to compute `BESSELJ` in a worksheet:
|
||||
|
||||
|
||||
```js
|
||||
{
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:3.14159 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', f:'BESSELJ(A1,A2)' }
|
||||
}
|
||||
```
|
||||
|
||||
**Array Formulae**
|
||||
|
||||
Array formulae are stored in the top-left cell of the array block. All cells
|
||||
of an array formula have a `F` field corresponding to the range. A single-cell
|
||||
formula can be distinguished from a plain formula by the presence of `F` field.
|
||||
|
||||
|
||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
|
||||
|
||||
```js
|
||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
|
||||
```
|
||||
|
||||
For a multi-cell array formula, every cell has the same array range but only the
|
||||
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
|
||||
|
||||
```js
|
||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
|
||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
|
||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
|
||||
```
|
||||
|
||||
|
||||
Utilities and writers are expected to check for the presence of a `F` field and
|
||||
ignore any possible formula element `f` in cells other than the starting cell.
|
||||
They are not expected to perform validation of the formulae!
|
||||
|
||||
|
||||
The `sheet_to_formulae` method generates one line per formula or array formula.
|
||||
Array formulae are rendered in the form `range=formula` while plain cells are
|
||||
rendered in the form `cell=formula or value`. Note that string literals are
|
||||
prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
|
||||
|
||||
| Storage Representation | Formats | Read | Write |
|
||||
|:-----------------------|:-------------------------|:-----:|:-----:|
|
||||
| A1-style strings | XLSX | ✔ | ✔ |
|
||||
|
@ -2334,6 +2357,269 @@ cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
|
|||
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
|
||||
formulae can be converted with regular expressions.
|
||||
|
||||
Shared formulae are decompressed and each cell has the formula corresponding to
|
||||
its cell. Writers generally do not attempt to generate shared formulae.
|
||||
|
||||
**Single-Cell Formulae**
|
||||
|
||||
For simple formulae, the `f` key of the desired cell can be set to the actual
|
||||
formula text. This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
|
||||
|
||||
```js
|
||||
var worksheet = {
|
||||
"!ref": "A1:A3",
|
||||
A1: { t:'n', v:1 },
|
||||
A2: { t:'n', v:2 },
|
||||
A3: { t:'n', v:3, f:'A1+A2' }
|
||||
};
|
||||
```
|
||||
|
||||
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
[ 1 ], // A1
|
||||
[ 2 ], // A2
|
||||
[ {t: "n", v: 3, f: "A1+A2"} ] // A3
|
||||
]);
|
||||
```
|
||||
|
||||
Cells with formula entries but no value will be serialized in a way that Excel
|
||||
and other spreadsheet tools will recognize. This library will not automatically
|
||||
compute formula results! For example, the following worksheet will include the
|
||||
`BESSELJ` function but the result will not be available in JavaScript:
|
||||
|
||||
```js
|
||||
var worksheet = XLSX.utils.aoa_to_sheet([
|
||||
[ 3.14159, 2 ], // Row "1"
|
||||
[ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
|
||||
}
|
||||
```
|
||||
|
||||
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
|
||||
offers a formula calculator component for evaluating expressions, updating
|
||||
values and dependent cells, and refreshing entire workbooks.
|
||||
|
||||
|
||||
**Array Formulae**
|
||||
|
||||
_Assign an array formula_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
|
||||
```
|
||||
|
||||
Array formulae are stored in the top-left cell of the array block. All cells
|
||||
of an array formula have a `F` field corresponding to the range. A single-cell
|
||||
formula can be distinguished from a plain formula by the presence of `F` field.
|
||||
|
||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
|
||||
```
|
||||
|
||||
For a multi-cell array formula, every cell has the same array range but only the
|
||||
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
|
||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
|
||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
|
||||
```
|
||||
|
||||
Utilities and writers are expected to check for the presence of a `F` field and
|
||||
ignore any possible formula element `f` in cells other than the starting cell.
|
||||
They are not expected to perform validation of the formulae!
|
||||
|
||||
|
||||
**Dynamic Array Formulae**
|
||||
|
||||
_Assign a dynamic array formula_
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
|
||||
```
|
||||
|
||||
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
|
||||
file formats. They are represented like normal array formulae but have special
|
||||
cell metadata indicating that the formula should be allowed to adjust the range.
|
||||
|
||||
An array formula can be marked as dynamic by setting the cell's `D` property to
|
||||
true. The `F` range is expected but can be the set to the current cell:
|
||||
|
||||
```js
|
||||
// API function
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
|
||||
|
||||
// ... OR raw operations
|
||||
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
|
||||
```
|
||||
|
||||
**Localization with Function Names**
|
||||
|
||||
SheetJS operates at the file level. Excel stores formula expressions using the
|
||||
English (United States) function names. For non-English users, Excel uses a
|
||||
localized set of function names.
|
||||
|
||||
For example, when the computer language and region is set to French (France),
|
||||
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function. However,
|
||||
in the actual file, Excel stores `SUM(A1:C3)`.
|
||||
|
||||
**Prefixed "Future Functions"**
|
||||
|
||||
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
|
||||
stored in files. When writing formula expressions using these functions, the
|
||||
prefix is required for maximal compatibility:
|
||||
|
||||
```js
|
||||
// Broadest compatibility
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
|
||||
|
||||
// Can cause errors in spreadsheet software
|
||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
|
||||
```
|
||||
|
||||
When reading a file, the `xlfn` option preserves the prefixes.
|
||||
|
||||
|
||||
This list is growing with each Excel release.
|
||||
|
||||
```
|
||||
ACOT
|
||||
ACOTH
|
||||
AGGREGATE
|
||||
ARABIC
|
||||
BASE
|
||||
BETA.DIST
|
||||
BETA.INV
|
||||
BINOM.DIST
|
||||
BINOM.DIST.RANGE
|
||||
BINOM.INV
|
||||
BITAND
|
||||
BITLSHIFT
|
||||
BITOR
|
||||
BITRSHIFT
|
||||
BITXOR
|
||||
BYCOL
|
||||
BYROW
|
||||
CEILING.MATH
|
||||
CEILING.PRECISE
|
||||
CHISQ.DIST
|
||||
CHISQ.DIST.RT
|
||||
CHISQ.INV
|
||||
CHISQ.INV.RT
|
||||
CHISQ.TEST
|
||||
COMBINA
|
||||
CONFIDENCE.NORM
|
||||
CONFIDENCE.T
|
||||
COT
|
||||
COTH
|
||||
COVARIANCE.P
|
||||
COVARIANCE.S
|
||||
CSC
|
||||
CSCH
|
||||
DAYS
|
||||
DECIMAL
|
||||
ERF.PRECISE
|
||||
ERFC.PRECISE
|
||||
EXPON.DIST
|
||||
F.DIST
|
||||
F.DIST.RT
|
||||
F.INV
|
||||
F.INV.RT
|
||||
F.TEST
|
||||
FIELDVALUE
|
||||
FILTERXML
|
||||
FLOOR.MATH
|
||||
FLOOR.PRECISE
|
||||
FORMULATEXT
|
||||
GAMMA
|
||||
GAMMA.DIST
|
||||
GAMMA.INV
|
||||
GAMMALN.PRECISE
|
||||
GAUSS
|
||||
HYPGEOM.DIST
|
||||
IFNA
|
||||
IMCOSH
|
||||
IMCOT
|
||||
IMCSC
|
||||
IMCSCH
|
||||
IMSEC
|
||||
IMSECH
|
||||
IMSINH
|
||||
IMTAN
|
||||
ISFORMULA
|
||||
ISOMITTED
|
||||
ISOWEEKNUM
|
||||
LAMBDA
|
||||
LET
|
||||
LOGNORM.DIST
|
||||
LOGNORM.INV
|
||||
MAKEARRAY
|
||||
MAP
|
||||
MODE.MULT
|
||||
MODE.SNGL
|
||||
MUNIT
|
||||
NEGBINOM.DIST
|
||||
NORM.DIST
|
||||
NORM.INV
|
||||
NORM.S.DIST
|
||||
NORM.S.INV
|
||||
NUMBERVALUE
|
||||
PDURATION
|
||||
PERCENTILE.EXC
|
||||
PERCENTILE.INC
|
||||
PERCENTRANK.EXC
|
||||
PERCENTRANK.INC
|
||||
PERMUTATIONA
|
||||
PHI
|
||||
POISSON.DIST
|
||||
QUARTILE.EXC
|
||||
QUARTILE.INC
|
||||
QUERYSTRING
|
||||
RANDARRAY
|
||||
RANK.AVG
|
||||
RANK.EQ
|
||||
REDUCE
|
||||
RRI
|
||||
SCAN
|
||||
SEC
|
||||
SECH
|
||||
SEQUENCE
|
||||
SHEET
|
||||
SHEETS
|
||||
SKEW.P
|
||||
SORTBY
|
||||
STDEV.P
|
||||
STDEV.S
|
||||
T.DIST
|
||||
T.DIST.2T
|
||||
T.DIST.RT
|
||||
T.INV
|
||||
T.INV.2T
|
||||
T.TEST
|
||||
UNICHAR
|
||||
UNICODE
|
||||
UNIQUE
|
||||
VAR.P
|
||||
VAR.S
|
||||
WEBSERVICE
|
||||
WEIBULL.DIST
|
||||
XLOOKUP
|
||||
XOR
|
||||
Z.TEST
|
||||
```
|
||||
|
||||
|
||||
#### Row and Column Properties
|
||||
|
||||
|
||||
|
|
|
@ -10,14 +10,17 @@
|
|||
* [Parsing Workbooks](README.md#parsing-workbooks)
|
||||
* [Processing JSON and JS Data](README.md#processing-json-and-js-data)
|
||||
* [Processing HTML Tables](README.md#processing-html-tables)
|
||||
- [Working with the Workbook](README.md#working-with-the-workbook)
|
||||
* [Parsing and Writing Examples](README.md#parsing-and-writing-examples)
|
||||
- [Processing Data](README.md#processing-data)
|
||||
* [Modifying Workbook Structure](README.md#modifying-workbook-structure)
|
||||
* [Modifying Cell Values](README.md#modifying-cell-values)
|
||||
* [Modifying Other Worksheet / Workbook / Cell Properties](README.md#modifying-other-worksheet--workbook--cell-properties)
|
||||
- [Packaging and Releasing Data](README.md#packaging-and-releasing-data)
|
||||
* [Writing Workbooks](README.md#writing-workbooks)
|
||||
* [Writing Examples](README.md#writing-examples)
|
||||
* [Streaming Write](README.md#streaming-write)
|
||||
* [Generating JSON and JS Data](README.md#generating-json-and-js-data)
|
||||
* [Generating HTML Tables](README.md#generating-html-tables)
|
||||
* [Generating Single-Worksheet Snapshots](README.md#generating-single-worksheet-snapshots)
|
||||
- [Interface](README.md#interface)
|
||||
* [Parsing functions](README.md#parsing-functions)
|
||||
* [Writing functions](README.md#writing-functions)
|
||||
|
|
|
@ -38,6 +38,7 @@ bits/47_styxml.js
|
|||
bits/48_stybin.js
|
||||
bits/49_theme.js
|
||||
bits/50_styxls.js
|
||||
bits/51_xlmeta.js
|
||||
bits/52_calcchain.js
|
||||
bits/53_externlink.js
|
||||
bits/54_drawing.js
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
||||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/// <reference path="src/types.ts"/>
|
||||
|
||||
/* [MS-XLSB] 2.4.698 BrtMdtinfo */
|
||||
interface BrtMdtinfo {
|
||||
flags: number;
|
||||
version: number;
|
||||
name: string;
|
||||
}
|
||||
function parse_BrtMdtinfo(data: ReadableData, length: number): BrtMdtinfo {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data: BrtMdtinfo): RawData {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.697 BrtMdb */
|
||||
type Mdir = [number, number]; // "t", "v" in XLSX parlance
|
||||
type BrtMdb = Mdir[];
|
||||
function write_BrtMdb(mdb: BrtMdb): RawData {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for(var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.72 BrtBeginEsfmd */
|
||||
function write_BrtBeginEsfmd(cnt: number, name: string): RawData {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.73 BrtBeginEsmdb */
|
||||
function write_BrtBeginEsmdb(cnt: number, cm: boolean): RawData {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.34 Metadata */
|
||||
function parse_xlmeta_bin(data, name: string, _opts?: ParseXLMetaOptions): XLMeta {
|
||||
var out: XLMeta = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state: string[] = [];
|
||||
var pass = false;
|
||||
|
||||
recordhopper(data, (val, R_n, RT) => {
|
||||
switch(RT) {
|
||||
// case 0x014C: /* 'BrtBeginMetadata' */
|
||||
// case 0x014D: /* 'BrtEndMetadata' */
|
||||
// case 0x014E: /* 'BrtBeginEsmdtinfo' */
|
||||
// case 0x0150: /* 'BrtEndEsmdtinfo' */
|
||||
// case 0x0151: /* 'BrtBeginEsmdb' */
|
||||
// case 0x0152: /* 'BrtEndEsmdb' */
|
||||
// case 0x0153: /* 'BrtBeginEsfmd' */
|
||||
// case 0x0154: /* 'BrtEndEsfmd' */
|
||||
// case 0x0034: /* 'BrtBeginFmd' */
|
||||
// case 0x0035: /* 'BrtEndFmd' */
|
||||
// case 0x1000: /* 'BrtBeginDynamicArrayPr' */
|
||||
// case 0x1001: /* 'BrtEndDynamicArrayPr' */
|
||||
// case 0x138A: /* 'BrtBeginRichValueBlock' */
|
||||
// case 0x138B: /* 'BrtEndRichValueBlock' */
|
||||
|
||||
case 0x014F: /* 'BrtMdtinfo' */
|
||||
out.Types.push({name: (val as BrtMdtinfo).name});
|
||||
break;
|
||||
case 0x0033: /* 'BrtMdb' */
|
||||
break;
|
||||
|
||||
case 0x0023: /* 'BrtFRTBegin' */
|
||||
state.push(R_n); pass = true; break;
|
||||
case 0x0024: /* 'BrtFRTEnd' */
|
||||
state.pop(); pass = false; break;
|
||||
default:
|
||||
if((R_n||"").indexOf("Begin") > 0){/* empty */}
|
||||
else if((R_n||"").indexOf("End") > 0){/* empty */}
|
||||
else if(!pass || (opts.WTF && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 120000,
|
||||
flags: 0xD06AC0B0
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
/* [ESSTR] [ESMDX] */
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(0x0202));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
/* *FRT */
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/// <reference path="src/types.ts"/>
|
||||
|
||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
|
||||
/* 12.3.10 Metadata Part */
|
||||
function parse_xlmeta_xml(data: string, name: string, opts?: ParseXLMetaOptions): XLMeta {
|
||||
var out: XLMeta = { Types: [] };
|
||||
if(!data) return out;
|
||||
var pass = false;
|
||||
|
||||
data.replace(tagregex, (x: string, idx: number) => {
|
||||
var y: any = parsexmltag(x);
|
||||
switch(strip_ns(y[0])) {
|
||||
case '<?xml': break;
|
||||
|
||||
/* 18.9.8 */
|
||||
case '<metadata': case '</metadata>': break;
|
||||
|
||||
/* 18.9.11 */
|
||||
case '<metadataTypes': case '</metadataTypes>': break;
|
||||
|
||||
/* 18.9.10 */
|
||||
case '<metadataType':
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
|
||||
/* 18.9.4 */
|
||||
case '<futureMetadata': break;
|
||||
case '</futureMetadata>': break;
|
||||
|
||||
/* 18.9.1 */
|
||||
case '<bk>': break;
|
||||
case '</bk>': break;
|
||||
|
||||
/* 18.9.15 */
|
||||
case '<rc': break;
|
||||
case '</rc>': break;
|
||||
|
||||
/* 18.9.3 */
|
||||
case '<cellMetadata':
|
||||
case '</cellMetadata>': break;
|
||||
|
||||
/* 18.9.17 */
|
||||
case '<valueMetadata': break;
|
||||
case '</valueMetadata>': break;
|
||||
|
||||
/* 18.2.10 extLst CT_ExtensionList ? */
|
||||
case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
|
||||
|
||||
/* 18.2.7 ext CT_Extension + */
|
||||
case '<ext': pass=true; break; //TODO: check with versions of excel
|
||||
case '</ext>': pass=false; break;
|
||||
|
||||
default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in metadata');
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
/* TODO: coordinate with cell writing, pass flags */
|
||||
function write_xlmeta_xml(): string {
|
||||
var o = [XML_HEADER];
|
||||
o.push(`\
|
||||
<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">
|
||||
<metadataTypes count="1">
|
||||
<metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>
|
||||
</metadataTypes>
|
||||
<futureMetadata name="XLDAPR" count="1">
|
||||
<bk>
|
||||
<extLst>
|
||||
<ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">
|
||||
<xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>
|
||||
</ext>
|
||||
</extLst>
|
||||
</bk>
|
||||
</futureMetadata>
|
||||
<cellMetadata count="1">
|
||||
<bk>
|
||||
<rc t="1" v="0"/>
|
||||
</bk>
|
||||
</cellMetadata>
|
||||
</metadata>`);
|
||||
|
||||
return o.join("");
|
||||
}
|
|
@ -2,10 +2,13 @@ LIBFILES=$(wildcard src/*.ts)
|
|||
TSFILES=$(wildcard *.ts)
|
||||
ENTRIES=$(subst .ts,.js,$(TSFILES))
|
||||
|
||||
BAREJS=04_base64.js 59_vba.js 64_ftab.js
|
||||
BAREJS=04_base64.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js
|
||||
|
||||
.PHONY: all
|
||||
all: $(ENTRIES)
|
||||
all: $(ENTRIES) 51_xlmeta.js
|
||||
|
||||
51_xlmeta.js: 51_xlsxmeta.js 51_xlsbmeta.js
|
||||
cat $^ > $@
|
||||
|
||||
$(BAREJS): %.js: %.ts $(LIBFILES)
|
||||
npx esbuild $< --outfile=$@ --platform=browser --target=es5
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
declare type RawData = Uint8Array | number[];
|
||||
declare function recordhopper(data: RawData, cb:(val: any, R_n: string, RT: number)=>void): void;
|
||||
declare interface ReadableData {
|
||||
l: number;
|
||||
read_shift(t: 4): number;
|
||||
read_shift(t: any): any;
|
||||
}
|
||||
declare type ParseFunc<T> = (data: ReadableData, length: number) => T;
|
||||
declare var parse_XLWideString: ParseFunc<string>;
|
||||
|
||||
declare interface WritableData {
|
||||
l: number;
|
||||
write_shift(t: 4, val: number): void;
|
||||
write_shift(t: number, val: string|number, f?: string): any;
|
||||
}
|
||||
declare type WritableRawData = WritableData & RawData;
|
||||
interface BufArray {
|
||||
end(): RawData;
|
||||
next(sz: number): WritableData;
|
||||
push(buf: RawData): void;
|
||||
}
|
||||
declare function buf_array(): BufArray;
|
||||
declare function write_record(ba: BufArray, type: string, payload?: RawData, length?: number): void;
|
||||
declare function new_buf(sz: number): RawData & WritableData & ReadableData;
|
||||
|
||||
declare var tagregex: RegExp;
|
||||
declare var XML_HEADER: string;
|
||||
declare var RELS: any;
|
||||
declare function parsexmltag(tag: string, skip_root?: boolean, skip_LC?: boolean): object;
|
||||
declare function strip_ns(x: string): string;
|
||||
declare function write_UInt32LE(x: number, o?: WritableData): RawData;
|
||||
declare function write_XLWideString(data: string, o?: WritableData): RawData;
|
||||
declare function writeuint16(x: number): RawData;
|
||||
|
||||
|
||||
interface ParseXLMetaOptions {
|
||||
WTF?: number|boolean;
|
||||
}
|
||||
interface XLMDT {
|
||||
name: string;
|
||||
}
|
||||
interface XLMeta {
|
||||
Types: XLMDT[];
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.18.2",
|
||||
"version": "0.18.3",
|
||||
"author": "sheetjs",
|
||||
"description": "SheetJS Spreadsheet data parser and writer",
|
||||
"keywords": [
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c8fe8a48a8cfc3c480b02f0a6df75cc2aff1932d
|
||||
Subproject commit 8203afea252b2817ec0a67e18f3b7c9503d50b97
|
|
@ -833,7 +833,7 @@ export interface XLSX$Utils {
|
|||
cell_add_comment(cell: CellObject, text: string, author?: string): void;
|
||||
|
||||
/** Assign an Array Formula to a range */
|
||||
sheet_set_array_formula(ws: WorkSheet, range: Range|string, formula: string): WorkSheet;
|
||||
sheet_set_array_formula(ws: WorkSheet, range: Range|string, formula: string, dynamic?: boolean): WorkSheet;
|
||||
|
||||
/** Add an array of arrays of JS data to a worksheet */
|
||||
sheet_add_aoa<T>(ws: WorkSheet, data: T[][], opts?: SheetAOAOpts): WorkSheet;
|
||||
|
|
311
xlsx.flow.js
311
xlsx.flow.js
|
@ -4,7 +4,7 @@
|
|||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
|
||||
var XLSX = {};
|
||||
function make_xlsx_lib(XLSX){
|
||||
XLSX.version = '0.18.2';
|
||||
XLSX.version = '0.18.3';
|
||||
var current_codepage = 1200, current_ansi = 1252;
|
||||
/*:: declare var cptable:any; */
|
||||
/*global cptable:true, window */
|
||||
|
@ -3189,7 +3189,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
|||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
if(typeof Deno !== 'undefined') {
|
||||
/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
|
||||
if(enc) switch(enc) {
|
||||
if(enc && typeof payload == "string") switch(enc) {
|
||||
case "utf8": payload = new TextEncoder(enc).encode(payload); break;
|
||||
case "binary": payload = s2ab(payload); break;
|
||||
/* TODO: binary equivalent */
|
||||
|
@ -4144,44 +4144,6 @@ function encode_range_xls(r, opts)/*:string*/ {
|
|||
}
|
||||
return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
|
||||
}
|
||||
var OFFCRYPTO = {};
|
||||
|
||||
var make_offcrypto = function(O, _crypto) {
|
||||
var crypto;
|
||||
if(typeof _crypto !== 'undefined') crypto = _crypto;
|
||||
else if(typeof require !== 'undefined') {
|
||||
try { crypto = require('crypto'); }
|
||||
catch(e) { crypto = null; }
|
||||
}
|
||||
|
||||
O.rc4 = function(key, data) {
|
||||
var S = new Array(256);
|
||||
var c = 0, i = 0, j = 0, t = 0;
|
||||
for(i = 0; i != 256; ++i) S[i] = i;
|
||||
for(i = 0; i != 256; ++i) {
|
||||
j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
|
||||
t = S[i]; S[i] = S[j]; S[j] = t;
|
||||
}
|
||||
// $FlowIgnore
|
||||
i = j = 0; var out = new_raw_buf(data.length);
|
||||
for(c = 0; c != data.length; ++c) {
|
||||
i = (i + 1)&255;
|
||||
j = (j + S[i])%256;
|
||||
t = S[i]; S[i] = S[j]; S[j] = t;
|
||||
out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
O.md5 = function(hex) {
|
||||
if(!crypto) throw new Error("Unsupported crypto");
|
||||
return crypto.createHash('md5').update(hex).digest('hex');
|
||||
};
|
||||
};
|
||||
/*:: declare var crypto:any; */
|
||||
/*global crypto:true */
|
||||
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
|
||||
|
||||
function decode_row(rowstr/*:string*/)/*:number*/ { return parseInt(unfix_row(rowstr),10) - 1; }
|
||||
function encode_row(row/*:number*/)/*:string*/ { return "" + (row + 1); }
|
||||
function fix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
|
||||
|
@ -4351,6 +4313,9 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
|
|||
}
|
||||
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
|
||||
|
||||
function parse_Int32LE(data) {
|
||||
return data.read_shift(4, 'i');
|
||||
}
|
||||
function write_UInt32LE(x/*:number*/, o) {
|
||||
if (!o) o = new_buf(4);
|
||||
o.write_shift(4, x);
|
||||
|
@ -5016,8 +4981,8 @@ var ct2type/*{[string]:string}*/ = ({
|
|||
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
|
||||
|
||||
/* Metadata */
|
||||
"application/vnd.ms-excel.sheetMetadata": "TODO",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
|
||||
"application/vnd.ms-excel.sheetMetadata": "metadata",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
|
||||
|
||||
/* PivotCache */
|
||||
"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
|
||||
|
@ -5134,6 +5099,10 @@ var CT_LIST = (function(){
|
|||
xlsx: "application/vnd.ms-excel.macrosheet+xml",
|
||||
xlsb: "application/vnd.ms-excel.macrosheet"
|
||||
},
|
||||
metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
|
||||
xlsb: "application/vnd.ms-excel.sheetMetadata"
|
||||
},
|
||||
styles: { /* Styles */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
||||
xlsb: "application/vnd.ms-excel.styles"
|
||||
|
@ -5153,7 +5122,7 @@ function new_ct()/*:any*/ {
|
|||
workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
|
||||
rels:[], strs:[], comments:[], links:[],
|
||||
coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
|
||||
calcchains:[], vba: [], drawings: [],
|
||||
calcchains:[], vba: [], drawings: [], metadata: [],
|
||||
TODO:[], xmlns: "" }/*:any*/);
|
||||
}
|
||||
|
||||
|
@ -5252,6 +5221,7 @@ function write_ct(ct, opts)/*:string*/ {
|
|||
f3('vba');
|
||||
f3('comments');
|
||||
f3('drawings');
|
||||
f2('metadata');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -5318,7 +5288,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
|
|||
function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ {
|
||||
if(!relobj) relobj = {};
|
||||
if(!rels['!id']) rels['!id'] = {};
|
||||
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
if(!rels['!idx']) rels['!idx'] = 1;
|
||||
if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
rels['!idx'] = rId + 1;
|
||||
relobj.Id = 'rId' + rId;
|
||||
relobj.Type = type;
|
||||
relobj.Target = f;
|
||||
|
@ -11310,6 +11282,157 @@ function update_xfext(xf, xfext) {
|
|||
});
|
||||
}
|
||||
|
||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
||||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
||||
/* 18.6 Calculation Chain */
|
||||
function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ {
|
||||
var d = [];
|
||||
|
@ -12636,7 +12759,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
|
|||
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
|
||||
var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
|
||||
/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
|
||||
if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
|
||||
if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
|
||||
stack.push(name);
|
||||
break;
|
||||
|
||||
|
@ -14534,6 +14657,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
|
|||
}
|
||||
if(cell.l) ws['!links'].push([ref, cell.l]);
|
||||
if(cell.c) ws['!comments'].push([ref, cell.c]);
|
||||
if(cell.D) o.cm = 1;
|
||||
return writextag('c', v, o);
|
||||
}
|
||||
|
||||
|
@ -14710,6 +14834,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
|
|||
}
|
||||
safe_format(p, fmtid, fillid, opts, themes, styles);
|
||||
if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
|
||||
if(tag.cm && opts.xlmeta) {
|
||||
var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
|
||||
if(cm && cm.name == 'XLDAPR') p.D = true;
|
||||
}
|
||||
if(dense) {
|
||||
var _r = decode_cell(tag.r);
|
||||
if(!s[_r.r]) s[_r.r] = [];
|
||||
|
@ -15424,6 +15552,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
|
||||
XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
|
||||
|
||||
var cm, vm;
|
||||
|
||||
recordhopper(data, function ws_parse(val, R_n, RT) {
|
||||
if(end) return;
|
||||
switch(RT) {
|
||||
|
@ -15481,6 +15611,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
}
|
||||
if(!af && val.length > 3) p.f = val[3];
|
||||
}
|
||||
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
|
@ -15488,12 +15619,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
|
||||
var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
|
||||
}
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x0001: /* 'BrtCellBlank' */
|
||||
case 0x000C: /* 'BrtShortBlank' */
|
||||
if(!opts.sheetStubs || pass) break;
|
||||
p = ({t:'z',v:undefined}/*:any*/);
|
||||
p = ({t:'z',v:void 0}/*:any*/);
|
||||
C = val[0].c == -1 ? C + 1 : val[0].c;
|
||||
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
|
||||
else s[encode_col(C) + rr] = p;
|
||||
|
@ -15501,11 +15637,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
if(refguess.e.c < C) refguess.e.c = C;
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x00B0: /* 'BrtMergeCell' */
|
||||
merges.push(val); break;
|
||||
|
||||
case 0x0031: { /* 'BrtCellMeta' */
|
||||
cm = ((opts.xlmeta||{}).Types||[])[val-1];
|
||||
} break;
|
||||
|
||||
case 0x01EE: /* 'BrtHLink' */
|
||||
var rel = rels['!id'][val.relId];
|
||||
if(rel) {
|
||||
|
@ -15593,7 +15738,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
case 0x041A: /* 'BrtCFVO14' */
|
||||
case 0x0289: /* 'BrtCellIgnoreEC' */
|
||||
case 0x0451: /* 'BrtCellIgnoreEC14' */
|
||||
case 0x0031: /* 'BrtCellMeta' */
|
||||
case 0x024D: /* 'BrtCellSmartTagProperty' */
|
||||
case 0x025F: /* 'BrtCellWatch' */
|
||||
case 0x0234: /* 'BrtColor' */
|
||||
|
@ -16800,6 +16944,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) {
|
|||
return parse_xlink_xml((data/*:any*/), rel, name, opts);
|
||||
}
|
||||
|
||||
function parse_xlmeta(data, name/*:string*/, opts) {
|
||||
if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts);
|
||||
return parse_xlmeta_xml((data/*:any*/), name, opts);
|
||||
}
|
||||
|
||||
function write_wb(wb, name/*:string*/, opts) {
|
||||
return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
|
||||
}
|
||||
|
@ -16829,6 +16978,10 @@ function write_cc(data, name:string, opts) {
|
|||
return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
|
||||
}
|
||||
*/
|
||||
|
||||
function write_xlmeta(name/*:string*/) {
|
||||
return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
|
||||
}
|
||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
|
||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
|
||||
function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) {
|
||||
|
@ -19097,7 +19250,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
|
||||
/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
|
||||
/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
|
||||
/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
|
||||
/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE },
|
||||
/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
|
||||
/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
|
||||
/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
|
||||
|
@ -19323,7 +19476,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
|
||||
/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
|
||||
/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
|
||||
/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
|
||||
/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
|
||||
/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
|
||||
/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
|
||||
/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
|
||||
|
@ -19844,7 +19997,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
|
||||
/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
|
||||
/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
|
||||
/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
|
||||
/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" },
|
||||
/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
|
||||
/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
|
||||
/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
|
||||
|
@ -19884,9 +20037,27 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
|
||||
/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
|
||||
/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
|
||||
/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" },
|
||||
/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" },
|
||||
/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" },
|
||||
/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" },
|
||||
/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" },
|
||||
/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" },
|
||||
/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" },
|
||||
/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" },
|
||||
/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" },
|
||||
/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" },
|
||||
/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" },
|
||||
/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" },
|
||||
/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" },
|
||||
/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" },
|
||||
/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" },
|
||||
/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" },
|
||||
/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" },
|
||||
/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" },
|
||||
/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" },
|
||||
/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" },
|
||||
/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" },
|
||||
/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" },
|
||||
/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" },
|
||||
/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" },
|
||||
/*::[*/0xFFFF/*::]*/: { n:"" }
|
||||
};
|
||||
|
||||
|
@ -22740,9 +22911,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
|||
var wbrelsi = dir.workbooks[0].lastIndexOf("/");
|
||||
var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
|
||||
if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
|
||||
|
||||
if((dir.metadata || []).length >= 1) {
|
||||
/* TODO: MDX and other types of metadata */
|
||||
opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
|
||||
}
|
||||
|
||||
if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
|
||||
|
||||
|
||||
/* Numbers iOS hack */
|
||||
var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
|
||||
wsloop: for(i = 0; i != props.Worksheets; ++i) {
|
||||
|
@ -22978,6 +23156,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta(f));
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -22986,7 +23169,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
return zip;
|
||||
}
|
||||
|
||||
|
||||
/* this version does not reference XLSB write functions */
|
||||
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
_shapeid = 1024;
|
||||
if(wb && !wb.SSF) {
|
||||
|
@ -23108,6 +23291,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta_xml());
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -23161,6 +23349,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
|
|||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
|
||||
o.type = "binary";
|
||||
return read_plaintext(str, o);
|
||||
}
|
||||
|
||||
|
@ -23280,14 +23469,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
|
|||
}
|
||||
function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ {
|
||||
var oopts = {};
|
||||
var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
|
||||
if(o.compression) oopts.compression = 'DEFLATE';
|
||||
if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
|
||||
if(o.password) oopts.type = ftype;
|
||||
else switch(o.type) {
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
case "buffer":
|
||||
case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
|
||||
case "file": oopts.type = ftype; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
|
||||
|
@ -23811,7 +24001,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri
|
|||
};
|
||||
|
||||
/* set array formula and flush related cells */
|
||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
|
||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) {
|
||||
var rng = typeof range != "string" ? range : safe_decode_range(range);
|
||||
var rngstr = typeof range == "string" ? range : encode_range(range);
|
||||
for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
|
||||
|
@ -23819,7 +24009,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
|
|||
cell.t = 'n';
|
||||
cell.F = rngstr;
|
||||
delete cell.v;
|
||||
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
|
||||
if(R == rng.s.r && C == rng.s.c) {
|
||||
cell.f = formula;
|
||||
if(dynamic) cell.D = true;
|
||||
}
|
||||
}
|
||||
return ws;
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
|
||||
var XLSX = {};
|
||||
function make_xlsx_lib(XLSX){
|
||||
XLSX.version = '0.18.2';
|
||||
XLSX.version = '0.18.3';
|
||||
var current_codepage = 1200, current_ansi = 1252;
|
||||
/*global cptable:true, window */
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
|
@ -3114,7 +3114,7 @@ function write_dl(fname, payload, enc) {
|
|||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
if(typeof Deno !== 'undefined') {
|
||||
/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
|
||||
if(enc) switch(enc) {
|
||||
if(enc && typeof payload == "string") switch(enc) {
|
||||
case "utf8": payload = new TextEncoder(enc).encode(payload); break;
|
||||
case "binary": payload = s2ab(payload); break;
|
||||
/* TODO: binary equivalent */
|
||||
|
@ -4057,43 +4057,6 @@ function encode_range_xls(r, opts) {
|
|||
}
|
||||
return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
|
||||
}
|
||||
var OFFCRYPTO = {};
|
||||
|
||||
var make_offcrypto = function(O, _crypto) {
|
||||
var crypto;
|
||||
if(typeof _crypto !== 'undefined') crypto = _crypto;
|
||||
else if(typeof require !== 'undefined') {
|
||||
try { crypto = require('crypto'); }
|
||||
catch(e) { crypto = null; }
|
||||
}
|
||||
|
||||
O.rc4 = function(key, data) {
|
||||
var S = new Array(256);
|
||||
var c = 0, i = 0, j = 0, t = 0;
|
||||
for(i = 0; i != 256; ++i) S[i] = i;
|
||||
for(i = 0; i != 256; ++i) {
|
||||
j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
|
||||
t = S[i]; S[i] = S[j]; S[j] = t;
|
||||
}
|
||||
// $FlowIgnore
|
||||
i = j = 0; var out = new_raw_buf(data.length);
|
||||
for(c = 0; c != data.length; ++c) {
|
||||
i = (i + 1)&255;
|
||||
j = (j + S[i])%256;
|
||||
t = S[i]; S[i] = S[j]; S[j] = t;
|
||||
out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
O.md5 = function(hex) {
|
||||
if(!crypto) throw new Error("Unsupported crypto");
|
||||
return crypto.createHash('md5').update(hex).digest('hex');
|
||||
};
|
||||
};
|
||||
/*global crypto:true */
|
||||
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
|
||||
|
||||
function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
|
||||
function encode_row(row) { return "" + (row + 1); }
|
||||
function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
|
||||
|
@ -4258,6 +4221,9 @@ function sheet_add_aoa(_ws, data, opts) {
|
|||
}
|
||||
function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
|
||||
|
||||
function parse_Int32LE(data) {
|
||||
return data.read_shift(4, 'i');
|
||||
}
|
||||
function write_UInt32LE(x, o) {
|
||||
if (!o) o = new_buf(4);
|
||||
o.write_shift(4, x);
|
||||
|
@ -4923,8 +4889,8 @@ var ct2type/*{[string]:string}*/ = ({
|
|||
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
|
||||
|
||||
/* Metadata */
|
||||
"application/vnd.ms-excel.sheetMetadata": "TODO",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
|
||||
"application/vnd.ms-excel.sheetMetadata": "metadata",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
|
||||
|
||||
/* PivotCache */
|
||||
"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
|
||||
|
@ -5041,6 +5007,10 @@ var CT_LIST = (function(){
|
|||
xlsx: "application/vnd.ms-excel.macrosheet+xml",
|
||||
xlsb: "application/vnd.ms-excel.macrosheet"
|
||||
},
|
||||
metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
|
||||
xlsb: "application/vnd.ms-excel.sheetMetadata"
|
||||
},
|
||||
styles: { /* Styles */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
||||
xlsb: "application/vnd.ms-excel.styles"
|
||||
|
@ -5060,7 +5030,7 @@ function new_ct() {
|
|||
workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
|
||||
rels:[], strs:[], comments:[], links:[],
|
||||
coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
|
||||
calcchains:[], vba: [], drawings: [],
|
||||
calcchains:[], vba: [], drawings: [], metadata: [],
|
||||
TODO:[], xmlns: "" });
|
||||
}
|
||||
|
||||
|
@ -5159,6 +5129,7 @@ function write_ct(ct, opts) {
|
|||
f3('vba');
|
||||
f3('comments');
|
||||
f3('drawings');
|
||||
f2('metadata');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -5225,7 +5196,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
|
|||
function add_rels(rels, rId, f, type, relobj, targetmode) {
|
||||
if(!relobj) relobj = {};
|
||||
if(!rels['!id']) rels['!id'] = {};
|
||||
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
if(!rels['!idx']) rels['!idx'] = 1;
|
||||
if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
rels['!idx'] = rId + 1;
|
||||
relobj.Id = 'rId' + rId;
|
||||
relobj.Type = type;
|
||||
relobj.Target = f;
|
||||
|
@ -11209,6 +11182,157 @@ function update_xfext(xf, xfext) {
|
|||
});
|
||||
}
|
||||
|
||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
||||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
||||
/* 18.6 Calculation Chain */
|
||||
function parse_cc_xml(data) {
|
||||
var d = [];
|
||||
|
@ -12534,7 +12658,7 @@ ixti = f[1][1]; r = f[1][2];
|
|||
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
|
||||
var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
|
||||
/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
|
||||
if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
|
||||
if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
|
||||
stack.push(name);
|
||||
break;
|
||||
|
||||
|
@ -14432,6 +14556,7 @@ function write_ws_xml_cell(cell, ref, ws, opts) {
|
|||
}
|
||||
if(cell.l) ws['!links'].push([ref, cell.l]);
|
||||
if(cell.c) ws['!comments'].push([ref, cell.c]);
|
||||
if(cell.D) o.cm = 1;
|
||||
return writextag('c', v, o);
|
||||
}
|
||||
|
||||
|
@ -14608,6 +14733,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
|
|||
}
|
||||
safe_format(p, fmtid, fillid, opts, themes, styles);
|
||||
if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
|
||||
if(tag.cm && opts.xlmeta) {
|
||||
var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
|
||||
if(cm && cm.name == 'XLDAPR') p.D = true;
|
||||
}
|
||||
if(dense) {
|
||||
var _r = decode_cell(tag.r);
|
||||
if(!s[_r.r]) s[_r.r] = [];
|
||||
|
@ -15321,6 +15450,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
|
||||
XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
|
||||
|
||||
var cm, vm;
|
||||
|
||||
recordhopper(data, function ws_parse(val, R_n, RT) {
|
||||
if(end) return;
|
||||
switch(RT) {
|
||||
|
@ -15378,6 +15509,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
}
|
||||
if(!af && val.length > 3) p.f = val[3];
|
||||
}
|
||||
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
|
@ -15385,12 +15517,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
|
||||
var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
|
||||
}
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x0001: /* 'BrtCellBlank' */
|
||||
case 0x000C: /* 'BrtShortBlank' */
|
||||
if(!opts.sheetStubs || pass) break;
|
||||
p = ({t:'z',v:undefined});
|
||||
p = ({t:'z',v:void 0});
|
||||
C = val[0].c == -1 ? C + 1 : val[0].c;
|
||||
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
|
||||
else s[encode_col(C) + rr] = p;
|
||||
|
@ -15398,11 +15535,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
if(refguess.e.c < C) refguess.e.c = C;
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x00B0: /* 'BrtMergeCell' */
|
||||
merges.push(val); break;
|
||||
|
||||
case 0x0031: { /* 'BrtCellMeta' */
|
||||
cm = ((opts.xlmeta||{}).Types||[])[val-1];
|
||||
} break;
|
||||
|
||||
case 0x01EE: /* 'BrtHLink' */
|
||||
var rel = rels['!id'][val.relId];
|
||||
if(rel) {
|
||||
|
@ -15490,7 +15636,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
|
|||
case 0x041A: /* 'BrtCFVO14' */
|
||||
case 0x0289: /* 'BrtCellIgnoreEC' */
|
||||
case 0x0451: /* 'BrtCellIgnoreEC14' */
|
||||
case 0x0031: /* 'BrtCellMeta' */
|
||||
case 0x024D: /* 'BrtCellSmartTagProperty' */
|
||||
case 0x025F: /* 'BrtCellWatch' */
|
||||
case 0x0234: /* 'BrtColor' */
|
||||
|
@ -16695,6 +16840,11 @@ function parse_xlink(data, rel, name, opts) {
|
|||
return parse_xlink_xml((data), rel, name, opts);
|
||||
}
|
||||
|
||||
function parse_xlmeta(data, name, opts) {
|
||||
if(name.slice(-4)===".bin") return parse_xlmeta_bin((data), name, opts);
|
||||
return parse_xlmeta_xml((data), name, opts);
|
||||
}
|
||||
|
||||
function write_wb(wb, name, opts) {
|
||||
return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
|
||||
}
|
||||
|
@ -16724,6 +16874,10 @@ function write_cc(data, name:string, opts) {
|
|||
return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
|
||||
}
|
||||
*/
|
||||
|
||||
function write_xlmeta(name) {
|
||||
return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
|
||||
}
|
||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
|
||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
|
||||
function xlml_parsexmltag(tag, skip_root) {
|
||||
|
@ -18980,7 +19134,7 @@ var XLSBRecordEnum = {
|
|||
0x002E: { n:"BrtBorder", f:parse_BrtBorder },
|
||||
0x002F: { n:"BrtXF", f:parse_BrtXF },
|
||||
0x0030: { n:"BrtStyle" },
|
||||
0x0031: { n:"BrtCellMeta" },
|
||||
0x0031: { n:"BrtCellMeta", f:parse_Int32LE },
|
||||
0x0032: { n:"BrtValueMeta" },
|
||||
0x0033: { n:"BrtMdb" },
|
||||
0x0034: { n:"BrtBeginFmd" },
|
||||
|
@ -19206,7 +19360,7 @@ var XLSBRecordEnum = {
|
|||
0x014C: { n:"BrtBeginMetadata" },
|
||||
0x014D: { n:"BrtEndMetadata" },
|
||||
0x014E: { n:"BrtBeginEsmdtinfo" },
|
||||
0x014F: { n:"BrtMdtinfo" },
|
||||
0x014F: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
|
||||
0x0150: { n:"BrtEndEsmdtinfo" },
|
||||
0x0151: { n:"BrtBeginEsmdb" },
|
||||
0x0152: { n:"BrtEndEsmdb" },
|
||||
|
@ -19727,7 +19881,7 @@ var XLSBRecordEnum = {
|
|||
0x0835: { n:"BrtEndTimelineStyleElements" },
|
||||
0x0836: { n:"BrtDxf15" },
|
||||
0x0837: { n:"BrtBeginDxfs15" },
|
||||
0x0838: { n:"brtEndDxfs15" },
|
||||
0x0838: { n:"BrtEndDxfs15" },
|
||||
0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
|
||||
0x083A: { n:"BrtBeginItemUniqueNames" },
|
||||
0x083B: { n:"BrtEndItemUniqueNames" },
|
||||
|
@ -19767,9 +19921,27 @@ var XLSBRecordEnum = {
|
|||
0x085D: { n:"BrtModelTimeGroupingCalcCol" },
|
||||
0x0C00: { n:"BrtUid" },
|
||||
0x0C01: { n:"BrtRevisionPtr" },
|
||||
0x13e7: { n:"BrtBeginCalcFeatures" },
|
||||
0x13e8: { n:"BrtEndCalcFeatures" },
|
||||
0x13e9: { n:"BrtCalcFeature" },
|
||||
0x1000: { n:"BrtBeginDynamicArrayPr" },
|
||||
0x1001: { n:"BrtEndDynamicArrayPr" },
|
||||
0x138A: { n:"BrtBeginRichValueBlock" },
|
||||
0x138B: { n:"BrtEndRichValueBlock" },
|
||||
0x13D9: { n:"BrtBeginRichFilters" },
|
||||
0x13DA: { n:"BrtEndRichFilters" },
|
||||
0x13DB: { n:"BrtRichFilter" },
|
||||
0x13DC: { n:"BrtBeginRichFilterColumn" },
|
||||
0x13DD: { n:"BrtEndRichFilterColumn" },
|
||||
0x13DE: { n:"BrtBeginCustomRichFilters" },
|
||||
0x13DF: { n:"BrtEndCustomRichFilters" },
|
||||
0x13E0: { n:"BrtCustomRichFilter" },
|
||||
0x13E1: { n:"BrtTop10RichFilter" },
|
||||
0x13E2: { n:"BrtDynamicRichFilter" },
|
||||
0x13E4: { n:"BrtBeginRichSortCondition" },
|
||||
0x13E5: { n:"BrtEndRichSortCondition" },
|
||||
0x13E6: { n:"BrtRichFilterDateGroupItem" },
|
||||
0x13E7: { n:"BrtBeginCalcFeatures" },
|
||||
0x13E8: { n:"BrtEndCalcFeatures" },
|
||||
0x13E9: { n:"BrtCalcFeature" },
|
||||
0x13EB: { n:"BrtExternalLinksPr" },
|
||||
0xFFFF: { n:"" }
|
||||
};
|
||||
|
||||
|
@ -22622,9 +22794,16 @@ function parse_zip(zip, opts) {
|
|||
var wbrelsi = dir.workbooks[0].lastIndexOf("/");
|
||||
var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
|
||||
if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
|
||||
|
||||
if((dir.metadata || []).length >= 1) {
|
||||
/* TODO: MDX and other types of metadata */
|
||||
opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
|
||||
}
|
||||
|
||||
if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
|
||||
|
||||
|
||||
/* Numbers iOS hack */
|
||||
var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
|
||||
wsloop: for(i = 0; i != props.Worksheets; ++i) {
|
||||
|
@ -22857,6 +23036,11 @@ f = "docProps/app.xml";
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta(f));
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -22865,7 +23049,7 @@ f = "docProps/app.xml";
|
|||
return zip;
|
||||
}
|
||||
|
||||
|
||||
/* this version does not reference XLSB write functions */
|
||||
function write_zip_xlsx(wb, opts) {
|
||||
_shapeid = 1024;
|
||||
if(wb && !wb.SSF) {
|
||||
|
@ -22986,6 +23170,11 @@ f = "docProps/app.xml";
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta_xml());
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -23039,6 +23228,7 @@ function read_plaintext_raw(data, o) {
|
|||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
|
||||
o.type = "binary";
|
||||
return read_plaintext(str, o);
|
||||
}
|
||||
|
||||
|
@ -23157,14 +23347,15 @@ function write_zip_typeXLSX(wb, opts) {
|
|||
}
|
||||
function write_zip_denouement(z, o) {
|
||||
var oopts = {};
|
||||
var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
|
||||
if(o.compression) oopts.compression = 'DEFLATE';
|
||||
if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
|
||||
if(o.password) oopts.type = ftype;
|
||||
else switch(o.type) {
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
case "buffer":
|
||||
case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
|
||||
case "file": oopts.type = ftype; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
|
||||
|
@ -23682,7 +23873,7 @@ utils.cell_add_comment = function(cell, text, author) {
|
|||
};
|
||||
|
||||
/* set array formula and flush related cells */
|
||||
utils.sheet_set_array_formula = function(ws, range, formula) {
|
||||
utils.sheet_set_array_formula = function(ws, range, formula, dynamic) {
|
||||
var rng = typeof range != "string" ? range : safe_decode_range(range);
|
||||
var rngstr = typeof range == "string" ? range : encode_range(range);
|
||||
for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
|
||||
|
@ -23690,7 +23881,10 @@ utils.sheet_set_array_formula = function(ws, range, formula) {
|
|||
cell.t = 'n';
|
||||
cell.F = rngstr;
|
||||
delete cell.v;
|
||||
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
|
||||
if(R == rng.s.r && C == rng.s.c) {
|
||||
cell.f = formula;
|
||||
if(dynamic) cell.D = true;
|
||||
}
|
||||
}
|
||||
return ws;
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
989
xlsx.mini.js
989
xlsx.mini.js
File diff suppressed because it is too large
Load Diff
|
@ -3,7 +3,7 @@
|
|||
/*exported XLSX */
|
||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
|
||||
var XLSX = {};
|
||||
XLSX.version = '0.18.2';
|
||||
XLSX.version = '0.18.3';
|
||||
var current_codepage = 1200, current_ansi = 1252;
|
||||
|
||||
var VALID_ANSI = [ 874, 932, 936, 949, 950, 10000 ];
|
||||
|
@ -3186,7 +3186,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
|||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
if(typeof Deno !== 'undefined') {
|
||||
/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
|
||||
if(enc) switch(enc) {
|
||||
if(enc && typeof payload == "string") switch(enc) {
|
||||
case "utf8": payload = new TextEncoder(enc).encode(payload); break;
|
||||
case "binary": payload = s2ab(payload); break;
|
||||
/* TODO: binary equivalent */
|
||||
|
@ -4310,6 +4310,9 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
|
|||
}
|
||||
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
|
||||
|
||||
function parse_Int32LE(data) {
|
||||
return data.read_shift(4, 'i');
|
||||
}
|
||||
function write_UInt32LE(x/*:number*/, o) {
|
||||
if (!o) o = new_buf(4);
|
||||
o.write_shift(4, x);
|
||||
|
@ -4975,8 +4978,8 @@ var ct2type/*{[string]:string}*/ = ({
|
|||
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
|
||||
|
||||
/* Metadata */
|
||||
"application/vnd.ms-excel.sheetMetadata": "TODO",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
|
||||
"application/vnd.ms-excel.sheetMetadata": "metadata",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
|
||||
|
||||
/* PivotCache */
|
||||
"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
|
||||
|
@ -5093,6 +5096,10 @@ var CT_LIST = (function(){
|
|||
xlsx: "application/vnd.ms-excel.macrosheet+xml",
|
||||
xlsb: "application/vnd.ms-excel.macrosheet"
|
||||
},
|
||||
metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
|
||||
xlsb: "application/vnd.ms-excel.sheetMetadata"
|
||||
},
|
||||
styles: { /* Styles */
|
||||
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
||||
xlsb: "application/vnd.ms-excel.styles"
|
||||
|
@ -5112,7 +5119,7 @@ function new_ct()/*:any*/ {
|
|||
workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
|
||||
rels:[], strs:[], comments:[], links:[],
|
||||
coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
|
||||
calcchains:[], vba: [], drawings: [],
|
||||
calcchains:[], vba: [], drawings: [], metadata: [],
|
||||
TODO:[], xmlns: "" }/*:any*/);
|
||||
}
|
||||
|
||||
|
@ -5211,6 +5218,7 @@ function write_ct(ct, opts)/*:string*/ {
|
|||
f3('vba');
|
||||
f3('comments');
|
||||
f3('drawings');
|
||||
f2('metadata');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -5277,7 +5285,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
|
|||
function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ {
|
||||
if(!relobj) relobj = {};
|
||||
if(!rels['!id']) rels['!id'] = {};
|
||||
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
if(!rels['!idx']) rels['!idx'] = 1;
|
||||
if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
|
||||
rels['!idx'] = rId + 1;
|
||||
relobj.Id = 'rId' + rId;
|
||||
relobj.Type = type;
|
||||
relobj.Target = f;
|
||||
|
@ -11269,6 +11279,157 @@ function update_xfext(xf, xfext) {
|
|||
});
|
||||
}
|
||||
|
||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
|
||||
function parse_xlmeta_xml(data, name, opts) {
|
||||
var out = { Types: [] };
|
||||
if (!data)
|
||||
return out;
|
||||
var pass = false;
|
||||
data.replace(tagregex, function(x, idx) {
|
||||
var y = parsexmltag(x);
|
||||
switch (strip_ns(y[0])) {
|
||||
case "<?xml":
|
||||
break;
|
||||
case "<metadata":
|
||||
case "</metadata>":
|
||||
break;
|
||||
case "<metadataTypes":
|
||||
case "</metadataTypes>":
|
||||
break;
|
||||
case "<metadataType":
|
||||
out.Types.push({ name: y.name });
|
||||
break;
|
||||
case "<futureMetadata":
|
||||
break;
|
||||
case "</futureMetadata>":
|
||||
break;
|
||||
case "<bk>":
|
||||
break;
|
||||
case "</bk>":
|
||||
break;
|
||||
case "<rc":
|
||||
break;
|
||||
case "</rc>":
|
||||
break;
|
||||
case "<cellMetadata":
|
||||
case "</cellMetadata>":
|
||||
break;
|
||||
case "<valueMetadata":
|
||||
break;
|
||||
case "</valueMetadata>":
|
||||
break;
|
||||
case "<extLst":
|
||||
case "<extLst>":
|
||||
case "</extLst>":
|
||||
case "<extLst/>":
|
||||
break;
|
||||
case "<ext":
|
||||
pass = true;
|
||||
break;
|
||||
case "</ext>":
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if (!pass && opts.WTF)
|
||||
throw new Error("unrecognized " + y[0] + " in metadata");
|
||||
}
|
||||
return x;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_xml() {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n <metadataTypes count="1">\n <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n </metadataTypes>\n <futureMetadata name="XLDAPR" count="1">\n <bk>\n <extLst>\n <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n </ext>\n </extLst>\n </bk>\n </futureMetadata>\n <cellMetadata count="1">\n <bk>\n <rc t="1" v="0"/>\n </bk>\n </cellMetadata>\n</metadata>');
|
||||
return o.join("");
|
||||
}
|
||||
function parse_BrtMdtinfo(data, length) {
|
||||
return {
|
||||
flags: data.read_shift(4),
|
||||
version: data.read_shift(4),
|
||||
name: parse_XLWideString(data, length - 8)
|
||||
};
|
||||
}
|
||||
function write_BrtMdtinfo(data) {
|
||||
var o = new_buf(12 + 2 * data.name.length);
|
||||
o.write_shift(4, data.flags);
|
||||
o.write_shift(4, data.version);
|
||||
write_XLWideString(data.name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtMdb(mdb) {
|
||||
var o = new_buf(4 + 8 * mdb.length);
|
||||
o.write_shift(4, mdb.length);
|
||||
for (var i = 0; i < mdb.length; ++i) {
|
||||
o.write_shift(4, mdb[i][0]);
|
||||
o.write_shift(4, mdb[i][1]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_BrtBeginEsfmd(cnt, name) {
|
||||
var o = new_buf(8 + 2 * name.length);
|
||||
o.write_shift(4, cnt);
|
||||
write_XLWideString(name, o);
|
||||
return o.slice(0, o.l);
|
||||
}
|
||||
function write_BrtBeginEsmdb(cnt, cm) {
|
||||
var o = new_buf(8);
|
||||
o.write_shift(4, cnt);
|
||||
o.write_shift(4, cm ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
function parse_xlmeta_bin(data, name, _opts) {
|
||||
var out = { Types: [] };
|
||||
var opts = _opts || {};
|
||||
var state = [];
|
||||
var pass = false;
|
||||
recordhopper(data, function(val, R_n, RT) {
|
||||
switch (RT) {
|
||||
case 335:
|
||||
out.Types.push({ name: val.name });
|
||||
break;
|
||||
case 51:
|
||||
break;
|
||||
case 35:
|
||||
state.push(R_n);
|
||||
pass = true;
|
||||
break;
|
||||
case 36:
|
||||
state.pop();
|
||||
pass = false;
|
||||
break;
|
||||
default:
|
||||
if ((R_n || "").indexOf("Begin") > 0) {
|
||||
} else if ((R_n || "").indexOf("End") > 0) {
|
||||
} else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
|
||||
throw new Error("Unexpected record " + RT + " " + R_n);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
function write_xlmeta_bin() {
|
||||
var ba = buf_array();
|
||||
write_record(ba, "BrtBeginMetadata");
|
||||
write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
|
||||
write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
|
||||
name: "XLDAPR",
|
||||
version: 12e4,
|
||||
flags: 3496657072
|
||||
}));
|
||||
write_record(ba, "BrtEndEsmdtinfo");
|
||||
write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
|
||||
write_record(ba, "BrtBeginFmd");
|
||||
write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
|
||||
write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
|
||||
write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
|
||||
write_record(ba, "BrtFRTEnd");
|
||||
write_record(ba, "BrtEndFmd");
|
||||
write_record(ba, "BrtEndEsfmd");
|
||||
write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
|
||||
write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
|
||||
write_record(ba, "BrtEndEsmdb");
|
||||
write_record(ba, "BrtEndMetadata");
|
||||
return ba.end();
|
||||
}
|
||||
/* 18.6 Calculation Chain */
|
||||
function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ {
|
||||
var d = [];
|
||||
|
@ -12595,7 +12756,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
|
|||
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
|
||||
var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
|
||||
/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
|
||||
if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
|
||||
if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
|
||||
stack.push(name);
|
||||
break;
|
||||
|
||||
|
@ -14493,6 +14654,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
|
|||
}
|
||||
if(cell.l) ws['!links'].push([ref, cell.l]);
|
||||
if(cell.c) ws['!comments'].push([ref, cell.c]);
|
||||
if(cell.D) o.cm = 1;
|
||||
return writextag('c', v, o);
|
||||
}
|
||||
|
||||
|
@ -14669,6 +14831,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
|
|||
}
|
||||
safe_format(p, fmtid, fillid, opts, themes, styles);
|
||||
if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
|
||||
if(tag.cm && opts.xlmeta) {
|
||||
var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
|
||||
if(cm && cm.name == 'XLDAPR') p.D = true;
|
||||
}
|
||||
if(dense) {
|
||||
var _r = decode_cell(tag.r);
|
||||
if(!s[_r.r]) s[_r.r] = [];
|
||||
|
@ -15383,6 +15549,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
|
||||
XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
|
||||
|
||||
var cm, vm;
|
||||
|
||||
recordhopper(data, function ws_parse(val, R_n, RT) {
|
||||
if(end) return;
|
||||
switch(RT) {
|
||||
|
@ -15440,6 +15608,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
}
|
||||
if(!af && val.length > 3) p.f = val[3];
|
||||
}
|
||||
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
|
@ -15447,12 +15616,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
|
||||
var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
|
||||
}
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x0001: /* 'BrtCellBlank' */
|
||||
case 0x000C: /* 'BrtShortBlank' */
|
||||
if(!opts.sheetStubs || pass) break;
|
||||
p = ({t:'z',v:undefined}/*:any*/);
|
||||
p = ({t:'z',v:void 0}/*:any*/);
|
||||
C = val[0].c == -1 ? C + 1 : val[0].c;
|
||||
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
|
||||
else s[encode_col(C) + rr] = p;
|
||||
|
@ -15460,11 +15634,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
if(refguess.s.c > C) refguess.s.c = C;
|
||||
if(refguess.e.r < row.r) refguess.e.r = row.r;
|
||||
if(refguess.e.c < C) refguess.e.c = C;
|
||||
if(cm) {
|
||||
if(cm.name == 'XLDAPR') p.D = true;
|
||||
cm = void 0;
|
||||
}
|
||||
if(vm) vm = void 0;
|
||||
break;
|
||||
|
||||
case 0x00B0: /* 'BrtMergeCell' */
|
||||
merges.push(val); break;
|
||||
|
||||
case 0x0031: { /* 'BrtCellMeta' */
|
||||
cm = ((opts.xlmeta||{}).Types||[])[val-1];
|
||||
} break;
|
||||
|
||||
case 0x01EE: /* 'BrtHLink' */
|
||||
var rel = rels['!id'][val.relId];
|
||||
if(rel) {
|
||||
|
@ -15552,7 +15735,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
|||
case 0x041A: /* 'BrtCFVO14' */
|
||||
case 0x0289: /* 'BrtCellIgnoreEC' */
|
||||
case 0x0451: /* 'BrtCellIgnoreEC14' */
|
||||
case 0x0031: /* 'BrtCellMeta' */
|
||||
case 0x024D: /* 'BrtCellSmartTagProperty' */
|
||||
case 0x025F: /* 'BrtCellWatch' */
|
||||
case 0x0234: /* 'BrtColor' */
|
||||
|
@ -16759,6 +16941,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) {
|
|||
return parse_xlink_xml((data/*:any*/), rel, name, opts);
|
||||
}
|
||||
|
||||
function parse_xlmeta(data, name/*:string*/, opts) {
|
||||
if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts);
|
||||
return parse_xlmeta_xml((data/*:any*/), name, opts);
|
||||
}
|
||||
|
||||
function write_wb(wb, name/*:string*/, opts) {
|
||||
return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
|
||||
}
|
||||
|
@ -16788,6 +16975,10 @@ function write_cc(data, name:string, opts) {
|
|||
return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
|
||||
}
|
||||
*/
|
||||
|
||||
function write_xlmeta(name/*:string*/) {
|
||||
return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
|
||||
}
|
||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
|
||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
|
||||
function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) {
|
||||
|
@ -19056,7 +19247,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
|
||||
/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
|
||||
/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
|
||||
/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
|
||||
/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE },
|
||||
/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
|
||||
/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
|
||||
/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
|
||||
|
@ -19282,7 +19473,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
|
||||
/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
|
||||
/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
|
||||
/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
|
||||
/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
|
||||
/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
|
||||
/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
|
||||
/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
|
||||
|
@ -19803,7 +19994,7 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
|
||||
/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
|
||||
/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
|
||||
/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
|
||||
/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" },
|
||||
/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
|
||||
/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
|
||||
/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
|
||||
|
@ -19843,9 +20034,27 @@ var XLSBRecordEnum = {
|
|||
/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
|
||||
/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
|
||||
/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
|
||||
/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" },
|
||||
/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" },
|
||||
/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" },
|
||||
/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" },
|
||||
/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" },
|
||||
/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" },
|
||||
/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" },
|
||||
/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" },
|
||||
/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" },
|
||||
/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" },
|
||||
/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" },
|
||||
/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" },
|
||||
/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" },
|
||||
/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" },
|
||||
/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" },
|
||||
/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" },
|
||||
/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" },
|
||||
/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" },
|
||||
/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" },
|
||||
/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" },
|
||||
/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" },
|
||||
/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" },
|
||||
/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" },
|
||||
/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" },
|
||||
/*::[*/0xFFFF/*::]*/: { n:"" }
|
||||
};
|
||||
|
||||
|
@ -22699,9 +22908,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
|||
var wbrelsi = dir.workbooks[0].lastIndexOf("/");
|
||||
var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
|
||||
if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
|
||||
var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
|
||||
|
||||
if((dir.metadata || []).length >= 1) {
|
||||
/* TODO: MDX and other types of metadata */
|
||||
opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
|
||||
}
|
||||
|
||||
if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
|
||||
|
||||
|
||||
/* Numbers iOS hack */
|
||||
var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
|
||||
wsloop: for(i = 0; i != props.Worksheets; ++i) {
|
||||
|
@ -22937,6 +23153,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta(f));
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -22945,7 +23166,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
return zip;
|
||||
}
|
||||
|
||||
|
||||
/* this version does not reference XLSB write functions */
|
||||
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
_shapeid = 1024;
|
||||
if(wb && !wb.SSF) {
|
||||
|
@ -23067,6 +23288,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|||
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
||||
}
|
||||
|
||||
f = "xl/metadata." + wbext;
|
||||
zip_add_file(zip, f, write_xlmeta_xml());
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -23120,6 +23346,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
|
|||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
|
||||
o.type = "binary";
|
||||
return read_plaintext(str, o);
|
||||
}
|
||||
|
||||
|
@ -23239,14 +23466,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
|
|||
}
|
||||
function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ {
|
||||
var oopts = {};
|
||||
var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
|
||||
if(o.compression) oopts.compression = 'DEFLATE';
|
||||
if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
|
||||
if(o.password) oopts.type = ftype;
|
||||
else switch(o.type) {
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
case "buffer":
|
||||
case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
|
||||
case "file": oopts.type = ftype; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
|
||||
|
@ -23770,7 +23998,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri
|
|||
};
|
||||
|
||||
/* set array formula and flush related cells */
|
||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
|
||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) {
|
||||
var rng = typeof range != "string" ? range : safe_decode_range(range);
|
||||
var rngstr = typeof range == "string" ? range : encode_range(range);
|
||||
for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
|
||||
|
@ -23778,7 +24006,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
|
|||
cell.t = 'n';
|
||||
cell.F = rngstr;
|
||||
delete cell.v;
|
||||
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
|
||||
if(R == rng.s.r && C == rng.s.c) {
|
||||
cell.f = formula;
|
||||
if(dynamic) cell.D = true;
|
||||
}
|
||||
}
|
||||
return ws;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue