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. | ||||
|  | ||||
| 
 | ||||
| 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: | ||||
| 
 | ||||
|  | ||||
|  | ||||
| 
 | ||||
| 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: | ||||
| 
 | ||||
|  | ||||
| 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