This commit is contained in:
SheetJS 2022-08-22 23:20:02 -04:00
parent ceca03b7e1
commit 5499547bf9
28 changed files with 671 additions and 214 deletions

203
.spelling

@ -1,83 +1,88 @@
# xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com
SheetJS
sheetjs
js-xlsx
xls
xlsb
xlsx
docs.sheetjs.com
# Doc Structure
TabItem
DocCardList
# Excel-related terms
A1-style
A1-Style
AutoFilter
BIFF2
BIFF3
BIFF4
BIFF5
BIFF8
BIFF12
CFB
CSV
Chartsheet
Chartsheets
DBF
DIF
Dialogsheet
Dialogsheets
ECMA-376
FODS
FoxPro
IEEE754
JSON
Macrosheet
Macrosheets
Multiplan
ODF
ODS
OData
OpenDocument
OpenFormula
PRN
PivotTable
PivotTables
QPW
Quattro
RFC4180
RTF
SLK
SYLK
SpreadsheetML
TSV
TXT
UOS1
UOS2
Unhide
VBA
Visicalc
Chartsheet
WB1
WB2
WB3
WK1
WK2
WK3
WK4
WKS
WK_
WQ1
WQ2
WQ3
XLML
XLR
XLS
XLW
XLSB
XLSM
XLSX
chartsheet
Chartsheets
chartsheets
Dialogsheet
dialogsheet
Dialogsheets
dialogsheets
dBASE
Macrosheet
dialogsheet
dialogsheets
macrosheet
Macrosheets
macrosheets
tooltip
tooltips
# Third-party
Browserify
CDNjs
CommonJS
Deno
Ethercalc
ExtendScript
InDesign
IndexedDB
JavaScriptCore
LocalStorage
MacOS
NestJS
NetSuite
NPM
Nuxt
PhantomJS
Photoshop
ReactJS
Redis
RequireJS
Rollup
SessionStorage
SQLite
SuiteScripts
SystemJS
VueJS
WebKit
WebSQL
WK_
axios
iOS
iWork
nodejs
node.js
npm
unpkg
webpack
weex
标文通
# Other terms
1.x
@ -89,38 +94,109 @@ weex
7.x
8.x
9.x
ActiveX
APIs
ActiveX
ArrayBuffer
Base64
Booleans
Browserify
Bundlers
CMS
CS6
CapacitorJS
CommonJS
Cordova
Deno
Drash
Ethercalc
ExtendScript
FileReader
GatsbyJS
HTML
HTML5
IE
IE10
IE11
IE6
IE9
InDesign
IndexedDB
JS
JSX
JavaScriptCore
LLC
LocalStorage
Lume
MacOS
NPM
NestJS
NetSuite
NextJS
NoSQL
NodeJS
Nunjucks
Nuxt
NuxtJS
PhantomJS
Photoshop
README
UTF-8
RESTlets
ReactJS
Redis
RequireJS
Rollup
SQLite
SWC
SessionStorage
Snowpack
SuiteScript
SuiteScripts
Suitelets
SystemJS
Tauri
UI
UI5
URI
UTF-16
UTF-8
VBScript
ViteJS
VueJS
WMR
WSL
WebKit
WebSQL
Webpack
XHR
XMLHttpRequest
async
axios
bundler
bundlers
cleanroom
codepage
commonjs
config
customizable
datagrid
dataset
deduplication
destructuring
disambiguate
embeddable
encodings
filesystem
globals
iOS
iWork
javascript
lifecycle
metadata
natively
node.js
nodejs
npm
parsers
pre-built
pre-generated
prepend
@ -129,13 +205,15 @@ programmatically
repo
runtime
serverless
subfolder
submodule
transpiled
utils
commonjs
async
uncheck
unpkg
utils
vendoring
webpack
weex
- demos/altjs/README.md
ChakraCore
@ -198,11 +276,4 @@ vscode-data-preview
axios
superagent
LLC
Bundlers
JSON
QPW
XLML
XLS
XLSB
XLSX

@ -12,7 +12,7 @@ serve:
.PHONY: spell
spell:
npx spellchecker-cli -d .spelling -f 'docz/**/*.md*'
npx spellchecker-cli -d .spelling -f 'docz/**/*.md*' --no-suggestions
.PHONY: index
index: readme ## Rebuild site

@ -79,8 +79,8 @@ For general stability, "vendoring" modules is the recommended approach:
<div>1) Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current
version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a></div><br/>
2) Create a `vendor` subdirectory at the root of your project and move the
tarball to that folder. Add it to your project repository.
2) Create a `vendor` subfolder at the root of your project and move the tarball
to that folder. Add it to your project repository.
3) Install the tarball using a package manager:

@ -58,7 +58,7 @@ const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez")
### Reshaping the Array
For this example, the name will be the first name combined with the last name
(`row.name.first + " " + row.name.last`) and the birthday will be the subfield
(`row.name.first + " " + row.name.last`) and the birthday will be available at
`row.bio.birthday`. Using `Array#map`, the dataset can be massaged in one call:
```js
@ -109,8 +109,8 @@ additional styling options like cell styling and frozen rows.
By default, `json_to_sheet` creates a worksheet with a header row. In this case,
the headers come from the JS object keys: "name" and "birthday".
The headers are in cells A1 and B1. `XLSX.utils.sheet_add_aoa` can write text
values to the existing worksheet starting at cell A1:
The headers are in cells `A1` and `B1`. `XLSX.utils.sheet_add_aoa` can write
text values to the existing worksheet starting at cell `A1`:
```js
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });

@ -170,7 +170,7 @@ To run the example, save the following script to `SheetJSPhantom.js` in the same
folder as `phantomjs.exe` or `phantomjs` and run
```
./phantomjs SheetJSPhantom.js ## macOS / Linux
./phantomjs SheetJSPhantom.js ## MacOS / Linux
.\phantomjs.exe SheetJSPhantom.js ## windows
```

@ -965,7 +965,7 @@ As it uses `fetch`, this demo requires Node 18.
ViteJS adopted nascent `package.json` patterns. Version 0.18.10 implements the
patterns required for ViteJS 3.0.3. These patterns are evolving and a future
version of Vite may require more packaging changes.
version of ViteJS may require more packaging changes.
:::

@ -73,7 +73,7 @@ files and convert to CSV.
Older versions of IE do not support HTML5 File API but do support Base64.
On OSX you can get the Base64 encoding with:
On MacOS you can get the Base64 encoding with:
```bash
$ <target_file base64 | pbcopy

@ -5,7 +5,7 @@ sidebar_position: 17
# Clipboard Data
Spreadsheet software like Excel typically support copying and pasting cells and
data. This is implemented through the Clipboard ("Pasteboard" in OSX parlance).
data. This is implemented through the Clipboard ("Pasteboard" in MacOS).
When copying a selection of cells, Excel for Windows stores a screenshot of the
selected cells as an image. It also creates and stores a number of strings and
@ -159,7 +159,7 @@ Electron additionally supports binary operations using `Buffer` objects. This
support is considered "experimental" and is not guaranteed to work on any
platform. Issues should be raised with the Electron project
On the `macOS` platform, some versions of Excel store a packaged file with key
On the `MacOS` platform, some versions of Excel store a packaged file with key
`dyn.ah62d4qmxhk4d425try1g44pdsm11g55gsu1en5pcqzwc4y5tsz3gg3k`. The package is
a simple CFB file that can be parsed:

@ -81,7 +81,7 @@ duk_pop(ctx);
:::note
This demo was tested on macOS x64.
This demo was tested on MacOS x64.
:::
@ -444,15 +444,15 @@ hermes xlsx.hermes.js
:::warning Platform Limitations
JavaScriptCore is primarily deployed in macOS and iOS applications. There is
JavaScriptCore is primarily deployed in MacOS and iOS applications. There is
some experimental support through the Bun runtime, but production applications
intending to support Windows / Linux / Android should try to embed V8.
:::
iOS and OSX ship with the JavaScriptCore framework for running JS scripts from
iOS and MacOS ship with the JavaScriptCore framework for running JS code from
Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
passing is straightforward. The demo shows a standalone Swift example for OSX.
passing is straightforward. The demo shows a standalone Swift sample for MacOS.
Binary strings can be passed back and forth using `String.Encoding.isoLatin1`.
@ -502,9 +502,9 @@ The demo includes a sample `SheetJSCore` Wrapper class to simplify operations.
<details><summary><b>Complete Example</b> (click to show)</summary>
:::caution This demo only runs on macOS
:::caution This demo only runs on MacOS
This example requires macOS + Swift and will not work on Windows or Linux!
This example requires MacOS + Swift and will not work on Windows or Linux!
:::

@ -27,7 +27,7 @@ The ["JavaScript Engines"](./engines) section includes samples for JavaScript
engines used in the mobile app frameworks. SheetJS libraries have been tested
in the relevant engines and should "just work" with some caveats.
:::caution readFile and writeFile
:::caution `readFile` and `writeFile`
`XLSX.readFile` and `XLSX.writeFile` do not work in mobile apps! The demos
include platform-specific details for fetching file data for `XLSX.read` and
@ -39,7 +39,7 @@ provide, usually there are third-party modules to provide needed functionality.
:::
macOS is required for the iOS demos. The Android demos were tested on macOS.
MacOS is required for the iOS demos. The Android demos were tested on MacOS.
## React Native
@ -605,7 +605,7 @@ The app can be tested with the following sequence in the simulator:
![save file iOS](pathname:///mobile/quasar7a.png)
- Make sure "On My iPhone" is highlighted and select "Save"
- Click the Home icon again then select the SheetJSRN app
- Click the Home icon again then select the `SheetJSRN` app
- Click "Import data" and select `pres`:
![pick file iOS](pathname:///mobile/rnios2.png)
@ -735,7 +735,7 @@ with Angular and TypeScript is assumed.
<details><summary><b>Complete Example</b> (click to show)</summary>
0) Follow the official Environment Setup instructions (tested with "macOS + iOS")
0) Follow the official Environment Setup instructions (tested with "MacOS + iOS")
1) Create a skeleton NativeScript + Angular app:
@ -1011,7 +1011,7 @@ The iOS simulator runs iOS 15.5 on an iPhone SE 3rd generation.
:::
This demo will focus on VueJS and Cordova with the Quasar Vite starter project.
This demo will use the Quasar ViteJS starter project with VueJS and Cordova.
### Integration Details
@ -1274,7 +1274,7 @@ To test that reading works:
![Quasar Step 7 save file](pathname:///mobile/quasar7a.png)
- Make sure "On My iPhone" is highlighted and select "Save"
- Click the Home icon again then select the SheetJSQuasar app
- Click the Home icon again then select the `SheetJSQuasar` app
- Click the "Load" button, then select "Choose File" and select `pres`:
![Quasar Step 7 load file](pathname:///mobile/quasar7b.png)
@ -1381,7 +1381,7 @@ The iOS simulator runs iOS 15.5 on an iPod Touch 7th Gen.
:::warning Telemetry
Before starting this demo, manually disable telemetry. On Linux and macOS:
Before starting this demo, manually disable telemetry. On Linux and MacOS:
```bash
rm -rf ~/.ionic/

@ -29,7 +29,7 @@ This was tested against `next v12.2.5` on 2022 August 16.
:::
:::caution
:::info
At a high level, there are two ways to pull spreadsheet data into NextJS apps:
loading an asset module or performing the file read operations from the NextJS
@ -145,7 +145,7 @@ export async function getStaticProps(ctx) {
These routes require a NodeJS dynamic server. Static page generation will fail!
`getStaticProps` and `getStaticPaths` support SSG.
`getStaticProps` and `getStaticPaths` support static site generation (SSG).
`getServerSideProps` is suited for NodeJS hosted deployments where the workbook
changes frequently and a static site is undesirable.
@ -185,14 +185,14 @@ npx next telemetry status
```
1) Set up folder structure. At the end, a `pages` folder with a `sheets`
subfolder must be created. On Linux or macOS or WSL:
subfolder must be created. On Linux or MacOS or WSL:
```bash
mkdir -p pages/sheets/
```
2) Download the [test file](pathname:///next/sheetjs.xlsx) and place in the
project root. On Linux or macOS or WSL:
project root. On Linux or MacOS or WSL:
```bash
curl -LO https://docs.sheetjs.com/next/sheetjs.xlsx
@ -206,7 +206,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz next
4) Download test scripts:
Download and place the following scripts in the `pages` subdirectory:
Download and place the following scripts in the `pages` subfolder:
- [`index.js`](pathname:///next/index.js)
- [`getServerSideProps.js`](pathname:///next/getServerSideProps.js)
@ -214,7 +214,7 @@ Download and place the following scripts in the `pages` subdirectory:
- [`getStaticProps.js`](pathname:///next/getStaticProps.js)
Download [`[id].js`](pathname:///next/%5Bid%5D.js) and place in the
`pages/sheets` subdirectory.
`pages/sheets` subfolder.
:::caution Percent-Encoding in the script name
@ -223,7 +223,7 @@ browser saved the file to `%5Bid%5D.js`. rename the file.
:::
On Linux or macOS or WSL:
On Linux or MacOS or WSL:
```bash
cd pages
@ -255,7 +255,7 @@ The individual worksheets are available at
- http://localhost:3000/sheets/1
- http://localhost:3000/sheets/2
6) Stop the dev server and run a production build:
6) Stop the server and run a production build:
```bash
npx next build
@ -315,13 +315,13 @@ Route (pages) Size First Load JS
npx next export
```
The static site will be written to the `out` subdirectory, which can be hosted with
The static site will be written to the `out` subfolder, which can be hosted with
```bash
npx http-server out
```
The command will start a local webserver on port 8080.
The command will start a local HTTP server on port 8080.
</details>
@ -419,7 +419,7 @@ npx create-nuxt-app SheetJSNuxt
When prompted, enter the following options:
- `Project name`: press Enter (use default SheetJSNuxt)
- `Project name`: press Enter (use default `SheetJSNuxt`)
- `Programming language`: press Down Arrow (`TypeScript` selected) then Enter
- `Package manager`: select `Npm` and press Enter
- `UI framework`: select `None` and press Enter
@ -434,7 +434,7 @@ When prompted, enter the following options:
The project will be configured and modules will be installed.
2) Install the SheetJS library and start the dev server:
2) Install the SheetJS library and start the server:
```bash
cd SheetJSNuxt
@ -445,11 +445,10 @@ npm run dev
When the build finishes, the terminal will display a URL like:
```
Listening on: http://localhost:64688/ 05:41:11
No issues found. 05:41:11
Listening on: http://localhost:64688/
```
The dev server is listening on that URL. Open the link in a web browser.
The server is listening on that URL. Open the link in a web browser.
3) Download <https://sheetjs.com/pres.xlsx> and move to the `content` folder.
@ -492,7 +491,7 @@ in Excel. Add a new row to the bottom and save the file:
![Adding a new line to `pres.xlsx`](pathname:///nuxt/nuxl6.png)
The dev server terminal should show a line like:
The server terminal window should show a line like:
```
Updated ./content/pres.xlsx @nuxt/content 05:43:37
@ -502,7 +501,7 @@ The page should automatically refresh with the new content:
![Nuxt Demo end of step 6](pathname:///nuxt/nuxt6.png)
7) Stop the dev server (press `CTRL+C` in the terminal window) and run
7) Stop the server (press `CTRL+C` in the terminal window) and run
```bash
npm run generate
@ -519,3 +518,52 @@ the static nature is trivial: make another change in Excel and save. The page
will not change.
</details>
## Lume
Lume is a static site generator for the Deno platform.
`lume#loadData` can add custom loaders for data. The loader method receives a
path to the file, which can be read with `XLSX.readFile`. This should be added
to `_config.js`, like in the example below:
```js title="_config.js"
import lume from "lume/mod.ts";
import { readFile, utils } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
function wbLoader(path) {
const wb = readFile(path);
const res = wb.SheetNames.map(n => ({
name: n,
data: utils.sheet_to_json(wb.Sheets[n])
}));
return { data: res };
}
const site = lume();
const exts = [".xlsx", ".numbers", /* ... other supported extensions */];
// highlight-next-line
site.loadData(exts, wbLoader);
export default site;
```
The actual spreadsheets should be placed in the `_data` subfolder.
The variable name is the stem of the filename (`sheetjs` if `sheetjs.xlsx` or
`sheetjs.numbers` exists). A Nunjucks or JSX template can loop through the
worksheets and the data rows. The example assumes each worksheet has a `name` and `index` column:
```jsx title="index.jsx"
export default ({sheetjs}) => {
return (<>{(sheetjs.data).map(sheet => (<>
<h2>{sheet.name}</h2>
<table><thead><th>Name</th><th>Index</th></thead>
<tbody>{sheet.data.map(row => (<tr>
<td>{row.name}</td>
<td>{row.index}</td>
</tr>))}</tbody>
</table>
</>))}</>);
};
```

@ -169,7 +169,7 @@ of column attribute objects and an array of row objects. The former is used to
generate column headings and for indexing into the row objects.
The safest approach is to use an array of arrays for state and to generate
column objects that map to A1-style column headers.
column objects that map to A1-Style column headers.
The [React Data Grid demo](./grid#rows-and-columns-state) uses this approach
with the following column and row structure:

@ -161,7 +161,7 @@ of column attribute objects and an array of row objects. The former is used to
generate column headings and for indexing into the row objects.
The safest approach is to use an array of arrays for state and to generate
column objects that map to A1-style column headers.
column objects that map to A1-Style column headers.
The [Vue Table Lite demo](./grid#rows-and-columns-bindings) uses this approach
with the following column and row structure:

@ -196,7 +196,7 @@ of column attribute objects and an array of row objects. The former is used to
generate column headings and for indexing into the row objects.
The safest approach is to use an array of arrays for state and to generate
column objects that map to A1-style column headers.
column objects that map to A1-Style column headers.
`ngx-datatable` uses `prop` as the key and `name` for the column label:

@ -0,0 +1,337 @@
---
sidebar_position: 26
title: Local File Access
---
Reading and writing files require native support. `readFile` and `writeFile`
include support for some approaches but do not support every API. When an API
is not supported by `readFile` or `writeFile`, the underlying `read` and
`write` methods can be used.
This demo looks at various web APIs. More specific approaches for deployments
like mobile apps are covered in their respective demos.
:::note
Some snippets are also available in the "Common Use Cases" section:
- [Data Import](../solutions/input)
- [Data Export](../solutions/output)
:::
:::warning
Not all web APIs are supported in all browsers. For example, Firefox does not
support the "File System Access API".
Even when a browser technically supports a web API, it may be disabled in the
client browser. Some APIs do not give any feedback.
:::
## Binary Data
Modern browser APIs typically use typed arrays or `Blob` or `File` structures.
_Reading Binary Data_
Given a `Blob` or `File`, the underlying data cannot be read synchronously!
The callback-based approach uses a `FileReader`:
```js
const reader = new FileReader();
reader.onload = function(e) {
/* e.target.result is an ArrayBuffer */
const wb = XLSX.read(e.target.result);
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
}
reader.readAsArrayBuffer(file);
```
The Promise-based approach uses `Blob#arrayBuffer`:
```js
// usage: const wb = await blob_to_wb(blob);
async function blob_to_wb(blob) {
return XLSX.read(await blob.arrayBuffer());
}
```
_Writing Binary Data_
`XLSX.write` can generate `Uint8Array` results by passing `type: "buffer"`. A
`Blob` can be created by using the constructor:
```js
const u8 = XLSX.write(workbook, { type: "buffer", bookType: "xlsx" });
const blob = new Blob([u8], { type: "application/vnd.ms-excel" });
```
## Web Workers
:::warning
**None of the browser methods work from Web Worker contexts!**
Data operations with the Web APIs must happen in the browser main thread.
:::
Web Workers and main thread can transfer `ArrayBuffer` or `Uint8Array` objects.
When generating a file, the worker will call `XLSX.write` with type `buffer`
and transfer the result to the main thread to initiate a download.
When parsing a file, the main thread will use the web API to read a `File` or
`Blob`, extract the underlying `ArrayBuffer` and transfer to the Web Worker.
## HTML5 Download Attribute
_Writing Files_
`writeFile` will attempt a download in the browser using the attribute.
```js
XLSX.writeFile(wb, "SheetJS.xlsx");
```
## File API
_Reading Files_
In the `change` event of `<input type="file">`, `target` hold a list of files:
```js
async function handleFileAsync(e) {
/* get first file */
const file = e.target.files[0];
/* get raw data */
const data = await file.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* do something with the workbook here */
console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]))
}
input_dom_element.addEventListener("change", handleFileAsync, false);
```
## HTML Drag and Drop API
_Reading Files_
The `dataTransfer` property of the `drop` event holds a list of files:
```js
async function handleDropAsync(e) {
e.stopPropagation(); e.preventDefault();
/* get first file */
const f = e.dataTransfer.files[0];
/* get raw data */
const data = await f.arrayBuffer();
/* data is an ArrayBuffer */
const wb = XLSX.read(data);
/* do something with the workbook here */
console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]))
}
drop_dom_element.addEventListener("drop", handleDropAsync, false);
```
## File System Access API
_Reading Files_
`window.showOpenFilePicker` shows a file picker and resolves to an array of
file handles. When `multiple: false` is set, the array has one element.
The `getFile` method resolves to a `File` object whose data can be read with
the `arrayBuffer` method:
```js
/* Show picker and get data */
const [hFile] = await window.showOpenFilePicker({
types: [{
description: 'Spreadsheets',
accept: { 'application/vnd.ms-excel': ['.xlsx', '.xls', '.xlsb', /*...*/] }
}],
excludeAcceptAllOption: true,
multiple: false
});
const ab = await (await hFile.getFile()).arrayBuffer();
/* parse */
const wb = XLSX.read(ab);
/* do something with the workbook */
console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
```
_Writing Files_
`window.showSaveFilePicker` shows a file picker and resolves to a file handle.
The `createWritable` method resolves to a `FileSystemWritableFileStream`, which
readily accepts `Uint8Array` data from `XLSX.write`:
```js
/* Show picker and get handle to file */
const hFile = await window.showSaveFilePicker({
suggestedName: "SheetJS.xlsx",
types: [
{ description: 'Excel 2007+ (XLSX)', accept: { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'] } },
{ description: 'Excel 97-2004 (XLS)', accept: { 'application/vnd.ms-excel': ['.xls'] } },
{ description: 'Excel 2007+ Binary (XLSB)', accept: { 'application/vnd.ms-excel.sheet.binary.macroEnabled.12': ['.xlsb'] } },
/* note that each MIME type must be unique! */
]
});
const wstream = await hFile.createWritable();
/* get extension */
const ext = hFile.name.slice(hFile.name.lastIndexOf(".")+1)
/* write */
wstream.write(XLSX.write(wb, { bookType: ext, type: "buffer" }))
/* close stream to commit file */
wstream.close();
```
### Demo
<details><summary><b>Live Example</b> (click to show) </summary>
This live example reads a file then tries to save as XLSX.
```jsx live
function SheetJSRoundTripFileSystemAPI() { return ( <button onClick={async () => {
/* Show picker and get data */
const [rFile] = await window.showOpenFilePicker({
types: [{
description: 'Spreadsheets',
accept: { 'application/vnd.ms-excel': ['.xlsx', '.xls', '.xlsb', /*...*/] }
}],
excludeAcceptAllOption: true,
multiple: false
});
const ab = await (await rFile.getFile()).arrayBuffer();
/* parse */
const wb = XLSX.read(ab);
/* Show picker and get handle to file */
const wFile = await window.showSaveFilePicker({
suggestedName: "SheetJSRT.xlsx",
types: [ { description: 'XLSX', accept: { 'application/vnd.ms-excel': ['.xlsx'] } } ]
});
console.log(wFile);
const wstream = await wFile.createWritable();
/* write */
const buf = XLSX.write(wb, { bookType: "xlsx", type: "buffer" });
wstream.write(buf);
/* close stream to commit file */
wstream.close();
}}>Click to read then save as XLSX</button> ) }
```
</details>
## File and Directory Entries API
In the web browser, the File and Directory Entries API does not project to the
local file system. `cordova-plugin-file` *does* write to device in mobile apps!
_Writing Files_
```js
// Request File System Access
window.requestFileSystem(window.PERSISTENT, 0, (fs) => {
// Request a handle to "SheetJS.xlsx", making a new file if necessary
fs.root.getFile("SheetJS.xlsx", {create: true}, entry => {
// Request a FileWriter for writing data
entry.createWriter(writer => {
// The FileWriter API needs an actual Blob
const u8 = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
const data = new Blob([u8], { type: "application/vnd.ms-excel" });
// `onwriteend` is called on success, `onerror` called on error
writer.onwriteend = () => {}; writer.onerror = () => {};
// write the data
writer.write(data);
});
});
});
```
## Internet Explorer
Internet Explorer offered proprietary APIs that were not adopted by Chromium.
#### Blob API
_Writing Files_
IE10 and IE11 support `navigator.msSaveBlob`. `writeFile` will use the method.
#### VBScript
_Reading and Writing Files_
Internet Explorer 6-9 with VBScript support `Scripting.FileSystemObject`. This
is not supported in modern browsers.
This approach is implemented in the library `readFile` and `writeFile` methods.
It requires the shim script to be loaded before the main library script:
```html
<!-- load the shim script first -->
<script src="shim.min.js"></script>
<!-- then load the main script -->
<script src="xlsx.full.min.js"></script>
```
## Other Platforms
### NodeJS
`fs.readFileSync` and `fs.writeFileSync` allow for reading and writing files.
When using `require`, these are supported in `readFile` and `writeFile`:
```js
var XLSX = require("xlsx");
var wb = XLSX.readFile("sheetjs.numbers");
XLSX.writeFile(wb, "sheetjs.xls");
```
[Installation](../getting-started/installation/nodejs) has a special note for
use with NodeJS ECMAScript Modules:
```js
import { readFile, writeFile, set_fs } from 'xlsx';
import * as fs from 'fs';
set_fs(fs);
var wb = XLSX.readFile("sheetjs.numbers");
XLSX.writeFile(wb, "sheetjs.xls");
```
### Deno
`Deno.readFileSync` and `Deno.writeFileSync` are supported by `readFile` and
`writeFile` out of the box:
```js
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
const wb = XLSX.readFile("sheetjs.numbers");
XLSX.writeFile(wb, "sheetjs.xlsx");
```
### Apps
Desktop and mobile apps have their own specific APIs covered in separate demos:
- [Electron and other desktop apps](./desktop)
- [React Native and other mobile apps](./mobile)

@ -15,6 +15,7 @@ The demo projects include small runnable examples and short explainers.
- [`LocalStorage and SessionStorage`](./database#localstorage-and-sessionstorage)
- [`Web SQL Database`](./database#websql)
- [`IndexedDB`](./database#indexeddb)
- [`Local File Access`](./localfile)
### Frameworks

@ -37,7 +37,7 @@ the ending col `16383`:
## A1-Style
A1-style is the default address style in Lotus 1-2-3 and Excel.
A1-Style is the default address style in Lotus 1-2-3 and Excel.
Columns are specified with letters, counting from `A` to `Z`, then `AA` to `ZZ`,
then `AAA`. Some sample values, along with SheetJS column indices, are listed:
@ -126,7 +126,7 @@ var address = XLSX.utils.decode_cell("A2");
The argument is expected to be a string representing a single cell address.
_Generate an A1-style address string from a SheetJS cell address_
_Generate an A1-Style address string from a SheetJS cell address_
```js
var a1_addr = XLSX.utils.encode_cell({r:1, c:0});
@ -136,7 +136,7 @@ The argument is expected to be a SheetJS cell address
#### Cell Ranges
_Generate a SheetJS cell range from an A1-style range string_
_Generate a SheetJS cell range from an A1-Style range string_
```js
var range = XLSX.utils.decode_range("A1:D3");
@ -146,7 +146,7 @@ The argument is expected to be a string representing a range or a single cell
address. The single cell address is interpreted as a single cell range, so
`XLSX.utils.decode_range("D3")` is the same as `XLSX.utils.decode_range("D3:D3")`
_Generate an A1-style address string from a SheetJS cell address_
_Generate an A1-Style address string from a SheetJS cell address_
```js
var a1_range = XLSX.utils.encode_range({ s: { c: 0, r: 0 }, e: { c: 3, r: 2 } });

@ -15,7 +15,7 @@ Cell objects are plain JS objects with keys and values following the convention:
| `z` | number format string associated with the cell (if requested) |
| `w` | formatted text (if applicable) |
| | **Formulae** ([More Info](./features/formulae)) |
| `f` | cell formula encoded as an A1-style string (if applicable) |
| `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) |
| | **Other Cell Properties** ([More Info](./features)) |

@ -80,7 +80,7 @@ XLSX.write(wb, {Props:{Author:"SheetJS"}});
|:----------|:-----------------------------------------------------------------|
| `Sheet` | Name scope. Sheet Index (0 = first sheet) or `null` (Workbook) |
| `Name` | Case-sensitive name. Standard rules apply ** |
| `Ref` | A1-style Reference (`"Sheet1!$A$1:$D$20"`) |
| `Ref` | A1-Style Reference (`"Sheet1!$A$1:$D$20"`) |
| `Comment` | Comment (only applicable for XLS/XLSX/XLSB) |
Excel allows two sheet-scoped defined names to share the same name. However, a

@ -9,17 +9,17 @@ import TabItem from '@theme/TabItem';
<details><summary><b>Formulae File Format Support</b> (click to show)</summary>
The parser will translate from the storage representation to A1-style strings,
while the writer will translate from A1-style strings to the file format.
The parser will translate from the storage representation to A1-Style strings,
while the writer will translate from A1-Style strings to the file format.
| Formats | Parse | Write | Array | Dynamic | Storage Representation |
|:------------------|:-----:|:-----:|:-----:|:-------:|:-----------------------|
| XLSX / XLSM | ✔ | ✔ | ✔ | ✔ | A1-style strings |
| XLSX / XLSM | ✔ | ✔ | ✔ | ✔ | A1-Style strings |
| XLSB | ✔ | | ✔ | ✔ | BIFF parsed tokens |
| XLS | ✔ | | ✔ | | BIFF parsed tokens |
| XLML | ✔ | ✔ | ✔ | | RC-style strings |
| SYLK | ✔ | ✔ | | | A1 / RC-style strings |
| CSV / TXT | ✔ | ✔ | | | A1-style strings |
| CSV / TXT | ✔ | ✔ | | | A1-Style strings |
| ODS / FODS / UOS | ✔ | ✔ | | | OpenFormula strings |
| WK\* | ✔ | | | | Lotus parsed tokens |
| WQ\* / WB\* / QPW | | | | | Quattro Pro tokens |
@ -124,7 +124,7 @@ const workbook = XLSX.readFile("test.xlsx", { cellFormula: true });
## A1-Style Formulae
The A1-style formula string is stored in the `f` field of the cell object.
The A1-Style formula string is stored in the `f` field of the cell object.
Spreadsheet software typically represent formulae with a leading `=` sign, but
SheetJS formulae omit the `=`.
@ -132,7 +132,7 @@ SheetJS formulae omit the `=`.
For example, consider [this test file](pathname:///files/concat.xlsx):
![D1=CONCAT("Sheet", "JS")](pathname:///files/concat.png)
![`D1=CONCAT("Sheet", "JS")`](pathname:///files/concat.png)
```jsx live
/* The live editor requires this function wrapper */

@ -65,7 +65,7 @@ The read functions accept an options argument:
for files employing other encryption methods.
- Newer Excel functions are serialized with the `_xlfn.` prefix, hidden from the
user. SheetJS will strip `_xlfn.` normally. The `xlfn` option preserves them.
- WTF is mainly for development. By default, the parser will suppress read
- `WTF` is mainly for development. By default, the parser will suppress read
errors on single worksheets, allowing you to read from the worksheets that do
parse properly. Setting `WTF:true` forces those errors to be thrown.

@ -78,7 +78,7 @@ accepts an options argument:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-style cell) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell A1 |
@ -203,7 +203,7 @@ an options argument:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-style cell) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell A1 |
@ -352,7 +352,7 @@ an options argument:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-style cell) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell A1 |
@ -559,7 +559,7 @@ takes an options argument:
| `range` | Description |
| :--------------- | :-------------------------------------------------------- |
| (number) | Use worksheet range but set starting row to the value |
| (string) | Use specified range (A1-style bounded range string) |
| (string) | Use specified range (A1-Style bounded range string) |
| (default) | Use worksheet range (`ws['!ref']`) |
`header` is expected to be one of:

@ -5,7 +5,7 @@ hide_table_of_contents: true
# File Formats
![circo graph of format support](../img/formats.png)
![graph of format support](../img/formats.png)
![graph legend](../img/legend.png)
@ -48,17 +48,17 @@ range limits will be silently truncated:
| Format | Last Cell | Max Cols | Max Rows |
|:------------------------------------------|:-----------|---------:|---------:|
| Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
| Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
| Numbers 12.1 (NUMBERS) | ALL1000000 | 1000 | 1000000 |
| Quattro Pro 9+ (QPW) | IV1000000 | 256 | 1000000 |
| Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
| Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
| Excel 4.0 (XLS BIFF4) | IV16384 | 256 | 16384 |
| Excel 3.0 (XLS BIFF3) | IV16384 | 256 | 16384 |
| Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
| Lotus 1-2-3 R2 - R5 (WK1/WK3/WK4) | IV8192 | 256 | 8192 |
| Lotus 1-2-3 R1 (WKS) | IV2048 | 256 | 2048 |
| Excel 2007+ XML Formats (XLSX/XLSM) |`XFD1048576`| 16384 | 1048576 |
| Excel 2007+ Binary Format (XLSB BIFF12) |`XFD1048576`| 16384 | 1048576 |
| Numbers 12.1 (NUMBERS) |`ALL1000000`| 1000 | 1000000 |
| Quattro Pro 9+ (QPW) |`IV1000000 `| 256 | 1000000 |
| Excel 97-2004 (XLS BIFF8) |`IV65536 `| 256 | 65536 |
| Excel 5.0/95 (XLS BIFF5) |`IV16384 `| 256 | 16384 |
| Excel 4.0 (XLS BIFF4) |`IV16384 `| 256 | 16384 |
| Excel 3.0 (XLS BIFF3) |`IV16384 `| 256 | 16384 |
| Excel 2.0/2.1 (XLS BIFF2) |`IV16384 `| 256 | 16384 |
| Lotus 1-2-3 R2 - R5 (WK1/WK3/WK4) |`IV8192 `| 256 | 8192 |
| Lotus 1-2-3 R1 (WKS) |`IV2048 `| 256 | 2048 |
Excel 2003 SpreadsheetML range limits are governed by the version of Excel and
are not enforced by the writer.
@ -208,7 +208,7 @@ files compatible with Visual FoxPro extensions.
Multi-file extensions like external memos and tables are currently unsupported,
limited by the general ability to read arbitrary files in the web browser. The
reader understands DBF Level 7 extensions like DATETIME.
reader understands DBF Level 7 extensions like `DATETIME`.
#### Symbolic Link (SYLK)

@ -86,7 +86,7 @@ Tests utilize the mocha testing framework.
- <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs
The test suite also includes tests for various time zones. To change
the timezone locally, set the TZ environment variable:
the timezone locally, set the `TZ` environment variable:
```bash
$ env TZ="Asia/Kolkata" WTF=1 make test_misc
@ -107,5 +107,5 @@ files snapshot from [the repo](https://github.com/SheetJS/test_files/releases)
<http://github.com/SheetJS/test_files/releases/download/20170409/test_files.zip>
(download and unzip to the `test_files` subdirectory)
(download and unzip to the `test_files` subfolder)

@ -39,7 +39,7 @@ import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="wsl" label="Windows WSL">
The OSX/Linux workflow works in WSL. Initial setup is involved:
The MacOS/Linux workflow works in WSL. Initial setup is involved:
1) Install mercurial and subversion.
@ -66,7 +66,7 @@ sudo n 16
```
3) follow <https://github.com/paul-nelson-baker/git-openssl-shellscript> to
build and install a version of Git with OpenSSL:
build and install a version of Git with proper SSL support:
```bash
# Git does not support OpenSSL out of the box, must do this
@ -75,10 +75,10 @@ chmod +x compile-git-with-openssl.sh
./compile-git-with-openssl.sh
```
(instructions continued in the OSX/Linux part)
(instructions continued in the MacOS/Linux part)
</TabItem>
<TabItem value="osx" label="OSX/Linux">
<TabItem value="osx" label="MacOS/Linux">
Initial setup:

@ -8,9 +8,9 @@ title: Overview
![License](https://img.shields.io/github/license/SheetJS/sheetjs)
[![Build Status](https://img.shields.io/github/workflow/status/sheetjs/sheetjs/Tests:%20node.js)](https://github.com/SheetJS/sheetjs/actions)
[![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/SheetJS/sheetjs)](https://snyk.io/test/github/SheetJS/sheetjs)
[![Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/SheetJS/sheetjs)](https://snyk.io/test/github/SheetJS/sheetjs)
[![npm Downloads](https://img.shields.io/npm/dm/xlsx.svg)](https://cdn.sheetjs.com/)
[![GitHub Repo stars](https://img.shields.io/github/stars/SheetJS/sheetjs?style=social)](https://github.com/SheetJS/sheetjs)
[![GitHub stars](https://img.shields.io/github/stars/SheetJS/sheetjs?style=social)](https://github.com/SheetJS/sheetjs)
SheetJS Community Edition offers battle-tested open-source solutions for
extracting useful data from almost any complex spreadsheet and generating new
@ -220,6 +220,6 @@ This,is,a,Test
### Supported File Formats
![circo graph of format support](./img/formats.png)
![graph of format support](./img/formats.png)
![graph legend](./img/legend.png)

@ -4,51 +4,51 @@ var XLSX = require('xlsx');
var Busboy = require('busboy');
exports.handler = function(event, context, callback) {
if(event.requestContext.http.method == "GET") {
/* make workbook */
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
/* write to XLSX file in base64 encoding */
var body = XLSX.write(wb, {type:"base64", bookType: "xlsx"});
/* mark as attached file */
var headers = { "Content-Disposition": 'attachment; filename="SheetJSLambda.xlsx"'};
/* Send back data */
callback(null, {
statusCode: 200,
isBase64Encoded: true,
body: body,
headers: headers
});
return;
}
if(event.requestContext.http.method == "GET") {
/* make workbook */
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
/* write to XLSX file in base64 encoding */
var body = XLSX.write(wb, {type:"base64", bookType: "xlsx"});
/* mark as attached file */
var headers = { "Content-Disposition": 'attachment; filename="SheetJSLambda.xlsx"'};
/* Send back data */
callback(null, {
statusCode: 200,
isBase64Encoded: true,
body: body,
headers: headers
});
return;
}
/* set up busboy */
var ctype = event.headers['Content-Type']||event.headers['content-type'];
var bb = Busboy({headers:{'content-type':ctype}});
/* set up busboy */
var ctype = event.headers['Content-Type']||event.headers['content-type'];
var bb = Busboy({headers:{'content-type':ctype}});
/* busboy is evented; accumulate the fields and files manually */
var fields = {}, files = {};
bb.on('error', function(err) { callback(null, { body: err.message }); });
bb.on('field', function(fieldname, val) {fields[fieldname] = val });
bb.on('file', function(fieldname, file, filename) {
/* concatenate the individual data buffers */
var buffers = [];
file.on('data', function(data) { buffers.push(data); });
file.on('end', function() { files[fieldname] = [Buffer.concat(buffers), filename]; });
});
/* busboy is evented; accumulate the fields and files manually */
var fields = {}, files = {};
bb.on('error', function(err) { callback(null, { body: err.message }); });
bb.on('field', function(fieldname, val) {fields[fieldname] = val });
bb.on('file', function(fieldname, file, filename) {
/* concatenate the individual data buffers */
var buffers = [];
file.on('data', function(data) { buffers.push(data); });
file.on('end', function() { files[fieldname] = [Buffer.concat(buffers), filename]; });
});
/* on the finish event, all of the fields and files are ready */
bb.on('finish', function() {
/* grab the first file */
var f = files["upload"];
if(!f) callback(new Error("Must submit a file for processing!"));
/* on the finish event, all of the fields and files are ready */
bb.on('finish', function() {
/* grab the first file */
var f = files["upload"];
if(!f) callback(new Error("Must submit a file for processing!"));
/* f[0] is a buffer */
var wb = XLSX.read(f[0]);
/* f[0] is a buffer */
var wb = XLSX.read(f[0]);
/* grab first worksheet and convert to CSV */
var ws = wb.Sheets[wb.SheetNames[0]];
callback(null, { statusCode: 200, body: XLSX.utils.sheet_to_csv(ws) });
});
/* grab first worksheet and convert to CSV */
var ws = wb.Sheets[wb.SheetNames[0]];
callback(null, { statusCode: 200, body: XLSX.utils.sheet_to_csv(ws) });
});
bb.end(Buffer.from(event.body, "base64"));
bb.end(Buffer.from(event.body, "base64"));
};

@ -1,26 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<defs>
<clipPath id="grid"><polygon points="0,0 0,1024 1024,1024 1024,780"/></clipPath>
<clipPath id="bars"><polygon points="0,0 1024,0 1024,780"/></clipPath>
</defs>
<polygon fill="#ffffff" points="0,0 0,1024 1024,1024 1024,0"/>
<polygon fill="#63deab" stroke="#ffffff" stroke-width="10" points="0,0 0,1024 1024,1024 1024,780"/>
<g clip-path="url(#bars)">
<rect x="288" y="160" width="192" height="1000" fill="#a2c5f0" stroke="#ffffff" stroke-width="10" />
<rect x="544" y="288" width="192" height="1000" fill="#ffbdbd" stroke="#ffffff" stroke-width="10" />
<rect x="800" y="64" width="192" height="1000" fill="#a2c5f0" stroke="#ffffff" stroke-width="10" />
</g>
<g clip-path="url(#grid)">
<line x1="0" y1="128" x2="1024" y2="128" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="256" x2="1024" y2="256" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="384" x2="1024" y2="384" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="512" x2="1024" y2="512" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="640" x2="1024" y2="640" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="768" x2="1024" y2="768" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="896" x2="1024" y2="896" stroke="#ffffff" stroke-width="10" />
<line x1="256" y1="0" x2="256" y2="1024" stroke="#ffffff" stroke-width="10" />
<line x1="512" y1="0" x2="512" y2="1024" stroke="#ffffff" stroke-width="10" />
<line x1="768" y1="0" x2="768" y2="1024" stroke="#ffffff" stroke-width="10" />
</g>
<line x1="0" y1="0" x2="1024" y2="780" stroke="#ffffff" stroke-width="10" />
<defs>
<clipPath id="grid"><polygon points="0,0 0,1024 1024,1024 1024,780"/></clipPath>
<clipPath id="bars"><polygon points="0,0 1024,0 1024,780"/></clipPath>
</defs>
<polygon fill="#ffffff" points="0,0 0,1024 1024,1024 1024,0"/>
<polygon fill="#63deab" stroke="#ffffff" stroke-width="10" points="0,0 0,1024 1024,1024 1024,780"/>
<g clip-path="url(#bars)">
<rect x="288" y="160" width="192" height="1000" fill="#a2c5f0" stroke="#ffffff" stroke-width="10" />
<rect x="544" y="288" width="192" height="1000" fill="#ffbdbd" stroke="#ffffff" stroke-width="10" />
<rect x="800" y="64" width="192" height="1000" fill="#a2c5f0" stroke="#ffffff" stroke-width="10" />
</g>
<g clip-path="url(#grid)">
<line x1="0" y1="128" x2="1024" y2="128" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="256" x2="1024" y2="256" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="384" x2="1024" y2="384" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="512" x2="1024" y2="512" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="640" x2="1024" y2="640" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="768" x2="1024" y2="768" stroke="#ffffff" stroke-width="10" />
<line x1="0" y1="896" x2="1024" y2="896" stroke="#ffffff" stroke-width="10" />
<line x1="256" y1="0" x2="256" y2="1024" stroke="#ffffff" stroke-width="10" />
<line x1="512" y1="0" x2="512" y2="1024" stroke="#ffffff" stroke-width="10" />
<line x1="768" y1="0" x2="768" y2="1024" stroke="#ffffff" stroke-width="10" />
</g>
<line x1="0" y1="0" x2="1024" y2="780" stroke="#ffffff" stroke-width="10" />
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB