forked from sheetjs/docs.sheetjs.com
excelapi
This commit is contained in:
parent
2e1eed486a
commit
4286792300
@ -17,40 +17,94 @@ It offers solutions for custom functions as well as task panes.
|
||||
Excel currently does not provide support for working with Apple Numbers files
|
||||
and some legacy file formats. SheetJS fills the gap.
|
||||
|
||||
This demo creates a new custom function to add much-needed functionality:
|
||||
This demo creates a new custom function `SHEETJS.EXTERN()` which tries to fetch
|
||||
an external spreadsheet and insert the data into the worksheet.
|
||||
|
||||
- `SHEETJS.EXTERN()` tries to fetch an external spreadsheet and insert the data
|
||||
into the worksheet.
|
||||
![`SHEETJS.EXTERN` output](pathname:///xlapi/xlfetch.png)
|
||||
|
||||
This demo focuses on the basic mechanics. Advanced topics like Excel Custom
|
||||
Function parameters are covered in the official Office JavaScript API docs.
|
||||
SheetJS worksheet metadata and other properties are covered in this doc site.
|
||||
|
||||
## Creating a new Add-in
|
||||
:::note
|
||||
|
||||
<details><summary><b>Initial Platform Setup</b> (click to show)</summary>
|
||||
This demo was last tested on 2023 April 20 against Excel 365 (version 2303)
|
||||
|
||||
The tool for generating Office Add-ins uses NodeJS and various libraries.
|
||||
Install [NodeJS LTS](https://nodejs.org/en/download/). After installing NodeJS,
|
||||
install dependencies in a new PowerShell window:
|
||||
:::
|
||||
|
||||
:::caution Excel Bugs
|
||||
|
||||
There was a binary data bug affecting `fetch` and Excel. It was resolved in
|
||||
version 2303. It is strongly encouraged to upgrade to the latest version of
|
||||
Excel 365 before running the demo.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [NodeJS module](/docs/getting-started/installation/nodejs) can be imported
|
||||
in an Excel Custom Functions project.
|
||||
|
||||
The [`sheet_to_json`](/docs/api/utilities#json) helper function can generate
|
||||
arrays of arrays of values based on the worksheet data. Excel custom functions
|
||||
transparently treat these as Dynamic Arrays.
|
||||
|
||||
This example fetches a file, parses the data, and extracts the first worksheet:
|
||||
|
||||
```js title="src\functions\functions.js"
|
||||
var XLSX = require("xlsx");
|
||||
|
||||
/**
|
||||
* Download file and write data
|
||||
* @customfunction
|
||||
* @param {string} url URL to fetch and parse
|
||||
* @returns {any[][]} Worksheet data
|
||||
*/
|
||||
async function extern(url) {
|
||||
try {
|
||||
/* Fetch Data */
|
||||
const res = await fetch(url);
|
||||
|
||||
/* Get Data */
|
||||
const ab = await res.arrayBuffer();
|
||||
|
||||
/* Parse Data */
|
||||
var wb = XLSX.read(ab);
|
||||
|
||||
/* get and return data */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]]; // get first worksheet
|
||||
var aoa = XLSX.utils.sheet_to_json(ws, { header: 1 }); // array of arrays
|
||||
return aoa;
|
||||
} catch(e) { return [[e.message || e]]; } // pass error back to Excel
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Demo
|
||||
|
||||
0) Clear the functions cache. For the tested version of Excel:
|
||||
|
||||
- Open File Explorer
|
||||
- Select the address bar and enter `%LOCALAPPDATA%\Microsoft\Office\16.0\Wef`
|
||||
- Delete `CustomFunctions` and empty Recycle Bin.
|
||||
|
||||
1) Install [NodeJS LTS](https://nodejs.org/en/download/).
|
||||
|
||||
2) Install dependencies in a new PowerShell window:
|
||||
|
||||
```powershell
|
||||
npm install -g yo bower generator-office
|
||||
```
|
||||
|
||||
</details>
|
||||
### Creating a new Add-in
|
||||
|
||||
<details><summary><b>Creating a new Project</b> (click to show)</summary>
|
||||
3) Run `yo office` from the command line. It will ask a few questions:
|
||||
|
||||
Run `yo office` from the command line. It will ask a few questions.
|
||||
|
||||
- "Choose a project type": "Excel Custom Functions Add-in project"
|
||||
- "Choose a project type": "Excel Custom Functions using a Shared Runtime"
|
||||
|
||||
- "Choose a script type": "JavaScript",
|
||||
|
||||
- "What do you want to name your add-in?": "SheetJSImport"
|
||||
|
||||
The script will create a new project and helpfully print the next steps:
|
||||
4) Start the dev process:
|
||||
|
||||
```powershell
|
||||
cd SheetJSImport
|
||||
@ -58,25 +112,33 @@ npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Running `npm start` will open up a terminal window and a new Excel window with
|
||||
the loaded add-in. Keep the terminal window open (it can be minimized). When
|
||||
you make a change, close both the Excel window and the terminal window before
|
||||
running `npm start` again.
|
||||
the loaded add-in. Keep the terminal window open.
|
||||
|
||||
## Integrating the SheetJS Library
|
||||
5) In `manifest.xml` , search for `Functions.NameSpace` . There will be an XML
|
||||
element with name `bt:String`. Change the `DefaultValue` attribute to `SHEETJS`:
|
||||
|
||||
The library can be installed like any other NodeJS module:
|
||||
```xml title="manifest.xml"
|
||||
<bt:ShortStrings>
|
||||
// highlight-next-line
|
||||
<bt:String id="Functions.Namespace" DefaultValue="SHEETJS"/>
|
||||
<bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!" />
|
||||
```
|
||||
|
||||
|
||||
6) Close the Excel window and the terminal window, then run `npm start` again.
|
||||
|
||||
### Integrating the SheetJS Library
|
||||
|
||||
7) Install the SheetJS library in the project
|
||||
|
||||
```bash
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
|
||||
```
|
||||
|
||||
To be sure the library is loaded, remove all of the existing functions from
|
||||
`src\functions\functions.js`. The new contents should be
|
||||
8) Replace `src\functions\functions.js` with the following:
|
||||
|
||||
```js src\functions\functions.js
|
||||
```js title="src\functions\functions.js"
|
||||
var XLSX = require("xlsx");
|
||||
|
||||
/**
|
||||
@ -89,132 +151,37 @@ function version() {
|
||||
}
|
||||
```
|
||||
|
||||
The `manifest.xml` should also be updated to reflect the function namespace.
|
||||
Search for `Functions.NameSpace` in the file and replace the line with:
|
||||
|
||||
```xml
|
||||
<bt:String id="Functions.Namespace" DefaultValue="SHEETJS"/>
|
||||
```
|
||||
|
||||
After making the change, save the files. Close the terminal window and the
|
||||
9) After making the change, save the files. Close the terminal window and the
|
||||
Excel window (do not save the Excel file). Re-run `npm start`.
|
||||
|
||||
In the new Excel window, enter the formula `=SHEETJS.VERSION()` in cell `E1`.
|
||||
You should see something similar to the following screenshot:
|
||||
10) In the new Excel window, enter the formula `=SHEETJS.VERSION()` in cell
|
||||
`E1`. You should see something similar to the following screenshot:
|
||||
|
||||
![`SHEETJS.VERSION` output](pathname:///files/xlcfversion.png)
|
||||
![`SHEETJS.VERSION` output](pathname:///xlapi/xlvers.png)
|
||||
|
||||
This indicates that the SheetJS library has been loaded.
|
||||
|
||||
## Dynamic Arrays and SheetJS Array of Arrays
|
||||
### Fetching Files from the Internet
|
||||
|
||||
The [`sheet_to_json`](/docs/api/utilities#json) helper function can generate
|
||||
arrays of arrays of values based on the worksheet data. Excel custom functions
|
||||
transparently treat these as Dynamic Arrays.
|
||||
|
||||
## Fetching Files from the Internet
|
||||
|
||||
For the next step, we will try to fetch data from an external resource.
|
||||
<https://sheetjs.com/pres.numbers> is an Apple Numbers file. Excel does not
|
||||
understand Numbers files and it will not open them.
|
||||
|
||||
<details><summary><b>Excel bug related to `fetch`</b> (click to show)</summary>
|
||||
|
||||
`fetch` is available to custom functions:
|
||||
|
||||
```js
|
||||
async function extern() {
|
||||
try {
|
||||
const url = "https://sheetjs.com/pres.numbers"; // URL to download
|
||||
const res = await fetch(url); // fetch data
|
||||
const ab = await res.arrayBuffer(); // get data as an array buffer
|
||||
|
||||
// DO SOMETHING WITH THE DATA HERE
|
||||
|
||||
} catch(e) { return e; } // pass error back to Excel
|
||||
}
|
||||
```
|
||||
|
||||
When fetching data, functions typically receive an `ArrayBuffer` which stores
|
||||
the file data. This is readily parsed with `read`:
|
||||
|
||||
```js
|
||||
var wb = XLSX.read(ab); // parse workbook
|
||||
```
|
||||
|
||||
**This is how it should work**.
|
||||
|
||||
At the time of writing, there are outstanding bugs in Excel with raw data.
|
||||
|
||||
For the purposes of this demo, a Base64-encoded file will be used. The
|
||||
workaround involves fetching that Base64 file, getting the text, and parsing
|
||||
with the [`base64` type:](/docs/api/parse-options#input-type)
|
||||
|
||||
```js
|
||||
async function extern() {
|
||||
try {
|
||||
const url = "https://sheetjs.com/pres.numbers.b64"; // URL to download
|
||||
const res = await fetch(url); // fetch data
|
||||
const text = await res.text(); // get data as an array buffer
|
||||
|
||||
var wb = XLSX.read(text, { type: "base64" });
|
||||
// DO SOMETHING WITH THE DATA HERE
|
||||
|
||||
} catch(e) { return e; } // pass error back to Excel
|
||||
}
|
||||
```
|
||||
|
||||
Base64-encoded files can be generated with PowerShell:
|
||||
|
||||
```powershell
|
||||
[convert]::ToBase64String([System.IO.File]::ReadAllBytes((Resolve-Path "path\to\file"))) > file.b64
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
The `.Sheets` property of the workbook object holds all of the worksheets and
|
||||
the `.SheetNames` property is an array of worksheet names. Picking the first
|
||||
worksheet is fairly straightforward:
|
||||
|
||||
```js
|
||||
var ws = wb.Sheets[wb.SheetNames[0]]; // get first worksheet
|
||||
```
|
||||
|
||||
This data can be converted to an Array of Arrays in one line:
|
||||
|
||||
```js
|
||||
var aoa = XLSX.utils.sheet_to_json(ws, {header: 1}); // get data as array of arrays
|
||||
```
|
||||
|
||||
To demonstrate the parsing ability, a Base64-encoded version of the file will
|
||||
be used. This file contains no binary characters and should "just work". Once
|
||||
the aforementioned Excel bug is fixed, the raw binary files can be used.
|
||||
|
||||
This new function should be added to `src\functions\functions.js`:
|
||||
11) Add the following code snippet to `src\functions\functions.js`:
|
||||
|
||||
```js src\functions\functions.js
|
||||
/**
|
||||
* Download file and write data
|
||||
* @customfunction
|
||||
* @param {string} url URL to fetch and parse
|
||||
* @returns {any[][]} Worksheet data
|
||||
*/
|
||||
async function extern() {
|
||||
async function extern(url) {
|
||||
try {
|
||||
/* URL */
|
||||
// const url = "https://sheetjs.com/pres.numbers"; // Once Excel bug is fixed
|
||||
const url = "https://sheetjs.com/pres.numbers.b64"; // workaround
|
||||
|
||||
/* Fetch Data */
|
||||
const res = await fetch(url);
|
||||
|
||||
/* Get Data */
|
||||
// const ab = await res.arrayBuffer(); // Once Excel bug is fixed
|
||||
const b64 = await res.text(); // workaround
|
||||
const ab = await res.arrayBuffer();
|
||||
|
||||
/* Parse Data */
|
||||
// var wb = XLSX.read(ab); // Once Excel bug is fixed
|
||||
var wb = XLSX.read(b64, { type: "base64" }); // workaround
|
||||
var wb = XLSX.read(ab);
|
||||
|
||||
/* get and return data */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]]; // get first worksheet
|
||||
@ -224,13 +191,12 @@ async function extern() {
|
||||
}
|
||||
```
|
||||
|
||||
After making the change, save the files. Close the terminal window and the
|
||||
12) After making the change, save the files. Close the terminal window and the
|
||||
Excel window (do not save the Excel file). Re-run `npm start`.
|
||||
|
||||
Enter the formula `=SHEETJS.EXTERN()` in cell `D1` and press Enter. Excel
|
||||
should pull in the data and generate a dynamic array:
|
||||
|
||||
![`SHEETJS.VERSION` output](pathname:///files/xlcfextern1.png)
|
||||
13) Enter the text `https://sheetjs.com/pres.numbers` in cell `D1`. Enter the
|
||||
formula `=SHEETJS.EXTERN(D1)` in cell `D2` and press Enter. Excel should pull
|
||||
in the data and generate a dynamic array.
|
||||
|
||||
:::note
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
"prism-react-renderer": "1.3.5",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.3.1"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB |
BIN
docz/static/xlapi/xlfetch.png
Normal file
BIN
docz/static/xlapi/xlfetch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
docz/static/xlapi/xlvers.png
Normal file
BIN
docz/static/xlapi/xlvers.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
@ -1,2 +1,3 @@
|
||||
const current = "0.19.3";
|
||||
export default current;
|
||||
//const version = "0.19.3";
|
||||
import { version } from "xlsx";
|
||||
export default version;
|
||||
|
Loading…
Reference in New Issue
Block a user