From 5499547bf921f2fc16f6b445f48df1b7f356389a Mon Sep 17 00:00:00 2001 From: SheetJS Date: Mon, 22 Aug 2022 23:20:02 -0400 Subject: [PATCH] webapi --- .spelling | 203 +++++++---- Makefile | 2 +- .../01-installation/04-nodejs.md | 4 +- docz/docs/02-getting-started/02-example.mdx | 6 +- docz/docs/03-demos/07-headless.md | 2 +- docz/docs/03-demos/09-bundler.md | 2 +- docz/docs/03-demos/12-legacy.md | 2 +- docz/docs/03-demos/17-clipboard.md | 4 +- docz/docs/03-demos/18-engines.md | 12 +- docz/docs/03-demos/19-mobile.md | 14 +- docz/docs/03-demos/20-content.md | 82 ++++- docz/docs/03-demos/21-react.md | 2 +- docz/docs/03-demos/22-vue.md | 2 +- docz/docs/03-demos/23-angular.md | 2 +- docz/docs/03-demos/27-localfile.md | 337 ++++++++++++++++++ docz/docs/03-demos/index.md | 1 + docz/docs/07-csf/01-general.md | 8 +- docz/docs/07-csf/02-cell.md | 2 +- docz/docs/07-csf/04-book.md | 2 +- docz/docs/07-csf/07-features/01-formulae.md | 12 +- docz/docs/08-api/05-parse-options.md | 2 +- docz/docs/08-api/09-utilities.md | 8 +- docz/docs/09-miscellany/01-formats.md | 26 +- docz/docs/09-miscellany/04-testing.md | 4 +- docz/docs/09-miscellany/05-contributing.md | 8 +- docz/docs/index.md | 6 +- docz/static/aws/index.js | 82 ++--- docz/static/img/logo.svg | 48 +-- 28 files changed, 671 insertions(+), 214 deletions(-) create mode 100644 docz/docs/03-demos/27-localfile.md diff --git a/.spelling b/.spelling index e326155d..1ef86a40 100644 --- a/.spelling +++ b/.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 + diff --git a/Makefile b/Makefile index 54334264..d92d1b4d 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/docz/docs/02-getting-started/01-installation/04-nodejs.md b/docz/docs/02-getting-started/01-installation/04-nodejs.md index 8c2941c0..a5cc0f33 100644 --- a/docz/docs/02-getting-started/01-installation/04-nodejs.md +++ b/docz/docs/02-getting-started/01-installation/04-nodejs.md @@ -79,8 +79,8 @@ For general stability, "vendoring" modules is the recommended approach:
1) Download the tarball (xlsx-{current}.tgz) for the desired version. The current version is available at https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz

-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: diff --git a/docz/docs/02-getting-started/02-example.mdx b/docz/docs/02-getting-started/02-example.mdx index a610b1cf..d58af6d7 100644 --- a/docz/docs/02-getting-started/02-example.mdx +++ b/docz/docs/02-getting-started/02-example.mdx @@ -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" }); diff --git a/docz/docs/03-demos/07-headless.md b/docz/docs/03-demos/07-headless.md index 61c04468..61c092bd 100644 --- a/docz/docs/03-demos/07-headless.md +++ b/docz/docs/03-demos/07-headless.md @@ -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 ``` diff --git a/docz/docs/03-demos/09-bundler.md b/docz/docs/03-demos/09-bundler.md index 8d2565a2..1dba2f68 100644 --- a/docz/docs/03-demos/09-bundler.md +++ b/docz/docs/03-demos/09-bundler.md @@ -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. ::: diff --git a/docz/docs/03-demos/12-legacy.md b/docz/docs/03-demos/12-legacy.md index a94154f4..3113f3f9 100644 --- a/docz/docs/03-demos/12-legacy.md +++ b/docz/docs/03-demos/12-legacy.md @@ -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 $ Complete Example (click to show) -:::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! ::: diff --git a/docz/docs/03-demos/19-mobile.md b/docz/docs/03-demos/19-mobile.md index 27085823..a283cf03 100644 --- a/docz/docs/03-demos/19-mobile.md +++ b/docz/docs/03-demos/19-mobile.md @@ -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.
Complete Example (click to show) -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/ diff --git a/docz/docs/03-demos/20-content.md b/docz/docs/03-demos/20-content.md index 8eca7ca7..5351cbca 100644 --- a/docz/docs/03-demos/20-content.md +++ b/docz/docs/03-demos/20-content.md @@ -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.
@@ -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 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. + +## 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 => (<> +

{sheet.name}

+ + {sheet.data.map(row => ( + + + ))} +
NameIndex
{row.name}{row.index}
+ ))}); +}; +``` diff --git a/docz/docs/03-demos/21-react.md b/docz/docs/03-demos/21-react.md index e56147ae..0a7882f1 100644 --- a/docz/docs/03-demos/21-react.md +++ b/docz/docs/03-demos/21-react.md @@ -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: diff --git a/docz/docs/03-demos/22-vue.md b/docz/docs/03-demos/22-vue.md index 837d77f4..2cafafbb 100644 --- a/docz/docs/03-demos/22-vue.md +++ b/docz/docs/03-demos/22-vue.md @@ -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: diff --git a/docz/docs/03-demos/23-angular.md b/docz/docs/03-demos/23-angular.md index 661d56ec..445c0c3e 100644 --- a/docz/docs/03-demos/23-angular.md +++ b/docz/docs/03-demos/23-angular.md @@ -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: diff --git a/docz/docs/03-demos/27-localfile.md b/docz/docs/03-demos/27-localfile.md new file mode 100644 index 00000000..60c078c6 --- /dev/null +++ b/docz/docs/03-demos/27-localfile.md @@ -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 ``, `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 + +
Live Example (click to show) + +This live example reads a file then tries to save as XLSX. + +```jsx live +function SheetJSRoundTripFileSystemAPI() { return ( ) } +``` + +
+ +## 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 + + + + +``` + +## 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) + diff --git a/docz/docs/03-demos/index.md b/docz/docs/03-demos/index.md index f55712d8..cd33f955 100644 --- a/docz/docs/03-demos/index.md +++ b/docz/docs/03-demos/index.md @@ -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 diff --git a/docz/docs/07-csf/01-general.md b/docz/docs/07-csf/01-general.md index 2545b626..db1b83c9 100644 --- a/docz/docs/07-csf/01-general.md +++ b/docz/docs/07-csf/01-general.md @@ -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 } }); diff --git a/docz/docs/07-csf/02-cell.md b/docz/docs/07-csf/02-cell.md index e8c45b15..1cf55d53 100644 --- a/docz/docs/07-csf/02-cell.md +++ b/docz/docs/07-csf/02-cell.md @@ -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)) | diff --git a/docz/docs/07-csf/04-book.md b/docz/docs/07-csf/04-book.md index 8373791d..957007f6 100644 --- a/docz/docs/07-csf/04-book.md +++ b/docz/docs/07-csf/04-book.md @@ -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 diff --git a/docz/docs/07-csf/07-features/01-formulae.md b/docz/docs/07-csf/07-features/01-formulae.md index 0617945b..84512e99 100644 --- a/docz/docs/07-csf/07-features/01-formulae.md +++ b/docz/docs/07-csf/07-features/01-formulae.md @@ -9,17 +9,17 @@ import TabItem from '@theme/TabItem';
Formulae File Format Support (click to show) -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 */ diff --git a/docz/docs/08-api/05-parse-options.md b/docz/docs/08-api/05-parse-options.md index 4fea0855..ffe64eb5 100644 --- a/docz/docs/08-api/05-parse-options.md +++ b/docz/docs/08-api/05-parse-options.md @@ -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. diff --git a/docz/docs/08-api/09-utilities.md b/docz/docs/08-api/09-utilities.md index 35dd4150..806995aa 100644 --- a/docz/docs/08-api/09-utilities.md +++ b/docz/docs/08-api/09-utilities.md @@ -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: diff --git a/docz/docs/09-miscellany/01-formats.md b/docz/docs/09-miscellany/01-formats.md index 2f0ea9db..c7bf2695 100644 --- a/docz/docs/09-miscellany/01-formats.md +++ b/docz/docs/09-miscellany/01-formats.md @@ -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) diff --git a/docz/docs/09-miscellany/04-testing.md b/docz/docs/09-miscellany/04-testing.md index 00ecf7a6..578b5876 100644 --- a/docz/docs/09-miscellany/04-testing.md +++ b/docz/docs/09-miscellany/04-testing.md @@ -86,7 +86,7 @@ Tests utilize the mocha testing framework. - 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) -(download and unzip to the `test_files` subdirectory) +(download and unzip to the `test_files` subfolder) diff --git a/docz/docs/09-miscellany/05-contributing.md b/docz/docs/09-miscellany/05-contributing.md index 45cdac69..72e3af7c 100644 --- a/docz/docs/09-miscellany/05-contributing.md +++ b/docz/docs/09-miscellany/05-contributing.md @@ -39,7 +39,7 @@ import TabItem from '@theme/TabItem'; -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 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) - + Initial setup: diff --git a/docz/docs/index.md b/docz/docs/index.md index 03e571e0..0c274990 100644 --- a/docz/docs/index.md +++ b/docz/docs/index.md @@ -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) diff --git a/docz/static/aws/index.js b/docz/static/aws/index.js index ad84b202..7dbfe84c 100644 --- a/docz/static/aws/index.js +++ b/docz/static/aws/index.js @@ -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")); }; diff --git a/docz/static/img/logo.svg b/docz/static/img/logo.svg index 5fe8eb5f..e611094e 100644 --- a/docz/static/img/logo.svg +++ b/docz/static/img/logo.svg @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +