UNPKG

110 kBMarkdownView Raw
1# [SheetJS js-xlsx](http://sheetjs.com)
2
3Parser and writer for various spreadsheet formats. Pure-JS cleanroom
4implementation from official specifications, related documents, and test files.
5Emphasis on parsing and writing robustness, cross-format feature compatibility
6with a unified JS representation, and ES3/ES5 browser compatibility back to IE6.
7
8This is the community version. We also offer a pro version with performance
9enhancements, additional features like styling, and dedicated support.
10
11
12[**Pro Version**](http://sheetjs.com/pro)
13
14[**Commercial Support**](http://sheetjs.com/support)
15
16[**Rendered Documentation**](http://docs.sheetjs.com/)
17
18[**In-Browser Demos**](http://sheetjs.com/demos)
19
20[**Source Code**](http://git.io/xlsx)
21
22[**Issues and Bug Reports**](https://github.com/sheetjs/js-xlsx/issues)
23
24[**File format support for known spreadsheet data formats:**](#file-formats)
25
26<details>
27 <summary><b>Graph of supported formats</b> (click to show)</summary>
28
29![circo graph of format support](formats.png)
30
31![graph legend](legend.png)
32
33</details>
34
35[**Browser Test**](http://oss.sheetjs.com/js-xlsx/tests/)
36
37[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
38
39[![Build Status](https://travis-ci.org/SheetJS/js-xlsx.svg?branch=master)](https://travis-ci.org/SheetJS/js-xlsx)
40[![Build Status](https://semaphoreci.com/api/v1/sheetjs/js-xlsx/branches/master/shields_badge.svg)](https://semaphoreci.com/sheetjs/js-xlsx)
41[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-xlsx/master.svg)](https://coveralls.io/r/SheetJS/js-xlsx?branch=master)
42[![Dependencies Status](https://david-dm.org/sheetjs/js-xlsx/status.svg)](https://david-dm.org/sheetjs/js-xlsx)
43[![npm Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
44[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
45
46## Table of Contents
47
48<details>
49 <summary><b>Expand to show Table of Contents</b></summary>
50
51<!-- toc -->
52
53- [Installation](#installation)
54 * [JS Ecosystem Demos](#js-ecosystem-demos)
55 * [Optional Modules](#optional-modules)
56 * [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
57- [Philosophy](#philosophy)
58- [Parsing Workbooks](#parsing-workbooks)
59 * [Parsing Examples](#parsing-examples)
60 * [Streaming Read](#streaming-read)
61- [Working with the Workbook](#working-with-the-workbook)
62 * [Parsing and Writing Examples](#parsing-and-writing-examples)
63- [Writing Workbooks](#writing-workbooks)
64 * [Writing Examples](#writing-examples)
65 * [Streaming Write](#streaming-write)
66- [Interface](#interface)
67 * [Parsing functions](#parsing-functions)
68 * [Writing functions](#writing-functions)
69 * [Utilities](#utilities)
70- [Common Spreadsheet Format](#common-spreadsheet-format)
71 * [General Structures](#general-structures)
72 * [Cell Object](#cell-object)
73 + [Data Types](#data-types)
74 + [Dates](#dates)
75 * [Sheet Objects](#sheet-objects)
76 + [Worksheet Object](#worksheet-object)
77 + [Chartsheet Object](#chartsheet-object)
78 + [Macrosheet Object](#macrosheet-object)
79 + [Dialogsheet Object](#dialogsheet-object)
80 * [Workbook Object](#workbook-object)
81 + [Workbook File Properties](#workbook-file-properties)
82 * [Workbook-Level Attributes](#workbook-level-attributes)
83 + [Defined Names](#defined-names)
84 + [Workbook Views](#workbook-views)
85 + [Miscellaneous Workbook Properties](#miscellaneous-workbook-properties)
86 * [Document Features](#document-features)
87 + [Formulae](#formulae)
88 + [Column Properties](#column-properties)
89 + [Row Properties](#row-properties)
90 + [Number Formats](#number-formats)
91 + [Hyperlinks](#hyperlinks)
92 + [Cell Comments](#cell-comments)
93 + [Sheet Visibility](#sheet-visibility)
94 + [VBA and Macros](#vba-and-macros)
95- [Parsing Options](#parsing-options)
96 * [Input Type](#input-type)
97 * [Guessing File Type](#guessing-file-type)
98- [Writing Options](#writing-options)
99 * [Supported Output Formats](#supported-output-formats)
100 * [Output Type](#output-type)
101- [Utility Functions](#utility-functions)
102 * [Array of Arrays Input](#array-of-arrays-input)
103 * [Array of Objects Input](#array-of-objects-input)
104 * [HTML Table Input](#html-table-input)
105 * [Formulae Output](#formulae-output)
106 * [Delimiter-Separated Output](#delimiter-separated-output)
107 + [UTF-16 Unicode Text](#utf-16-unicode-text)
108 * [HTML Output](#html-output)
109 * [JSON](#json)
110- [File Formats](#file-formats)
111 * [Excel 2007+ XML (XLSX/XLSM)](#excel-2007-xml-xlsxxlsm)
112 * [Excel 2.0-95 (BIFF2/BIFF3/BIFF4/BIFF5)](#excel-20-95-biff2biff3biff4biff5)
113 * [Excel 97-2004 Binary (BIFF8)](#excel-97-2004-binary-biff8)
114 * [Excel 2003-2004 (SpreadsheetML)](#excel-2003-2004-spreadsheetml)
115 * [Excel 2007+ Binary (XLSB, BIFF12)](#excel-2007-binary-xlsb-biff12)
116 * [Delimiter-Separated Values (CSV/TXT)](#delimiter-separated-values-csvtxt)
117 * [Other Workbook Formats](#other-workbook-formats)
118 + [Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123)](#lotus-1-2-3-wkswk1wk2wk3wk4123)
119 + [Quattro Pro (WQ1/WQ2/WB1/WB2/WB3/QPW)](#quattro-pro-wq1wq2wb1wb2wb3qpw)
120 + [OpenDocument Spreadsheet (ODS/FODS)](#opendocument-spreadsheet-odsfods)
121 + [Uniform Office Spreadsheet (UOS1/2)](#uniform-office-spreadsheet-uos12)
122 * [Other Single-Worksheet Formats](#other-single-worksheet-formats)
123 + [dBASE and Visual FoxPro (DBF)](#dbase-and-visual-foxpro-dbf)
124 + [Symbolic Link (SYLK)](#symbolic-link-sylk)
125 + [Lotus Formatted Text (PRN)](#lotus-formatted-text-prn)
126 + [Data Interchange Format (DIF)](#data-interchange-format-dif)
127 + [HTML](#html)
128 + [Rich Text Format (RTF)](#rich-text-format-rtf)
129 + [Ethercalc Record Format (ETH)](#ethercalc-record-format-eth)
130- [Testing](#testing)
131 * [Node](#node)
132 * [Browser](#browser)
133 * [Tested Environments](#tested-environments)
134 * [Test Files](#test-files)
135- [Contributing](#contributing)
136 * [OSX/Linux](#osxlinux)
137 * [Windows](#windows)
138 * [Tests](#tests)
139- [License](#license)
140- [References](#references)
141
142<!-- tocstop -->
143
144</details>
145
146## Installation
147
148In the browser, just add a script tag:
149
150```html
151<script lang="javascript" src="dist/xlsx.full.min.js"></script>
152```
153
154<details>
155 <summary><b>CDN Availability</b> (click to show)</summary>
156
157| CDN | URL |
158|-----------:|:-------------------------------------------|
159| `unpkg` | <https://unpkg.com/xlsx/> |
160| `jsDelivr` | <https://jsdelivr.com/package/npm/xlsx> |
161| `CDNjs` | <http://cdnjs.com/libraries/xlsx> |
162| `packd` | <https://bundle.run/xlsx@latest?name=XLSX> |
163
164`unpkg` makes the latest version available at:
165
166```html
167<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
168```
169
170</details>
171
172
173With [npm](https://www.npmjs.org/package/xlsx):
174
175```bash
176$ npm install xlsx
177```
178
179With [bower](http://bower.io/search/?q=js-xlsx):
180
181```bash
182$ bower install js-xlsx
183```
184
185### JS Ecosystem Demos
186
187The [`demos` directory](demos/) includes sample projects for:
188
189**Frameworks and APIs**
190- [`angularjs`](demos/angular/)
191- [`angular 2 / 4 / 5 / 6 and ionic`](demos/angular2/)
192- [`knockout`](demos/knockout/)
193- [`meteor`](demos/meteor/)
194- [`react and react-native`](demos/react/)
195- [`vue 2.x and weex`](demos/vue/)
196- [`XMLHttpRequest and fetch`](demos/xhr/)
197- [`nodejs server`](demos/server/)
198- [`databases and key/value stores`](demos/database/)
199- [`typed arrays and math`](demos/array/)
200
201**Bundlers and Tooling**
202- [`browserify`](demos/browserify/)
203- [`fusebox`](demos/fusebox/)
204- [`parcel`](demos/parcel/)
205- [`requirejs`](demos/requirejs/)
206- [`rollup`](demos/rollup/)
207- [`systemjs`](demos/systemjs/)
208- [`typescript`](demos/typescript/)
209- [`webpack 2.x`](demos/webpack/)
210
211**Platforms and Integrations**
212- [`electron application`](demos/electron/)
213- [`nw.js application`](demos/nwjs/)
214- [`Chrome / Chromium extensions`](demos/chrome/)
215- [`Adobe ExtendScript`](demos/extendscript/)
216- [`Headless Browsers`](demos/headless/)
217- [`canvas-datagrid`](demos/datagrid/)
218- [`Swift JSC and other engines`](demos/altjs/)
219- [`"serverless" functions`](demos/function/)
220- [`internet explorer`](demos/oldie/)
221
222### Optional Modules
223
224<details>
225 <summary><b>Optional features</b> (click to show)</summary>
226
227The node version automatically requires modules for additional features. Some
228of these modules are rather large in size and are only needed in special
229circumstances, so they do not ship with the core. For browser use, they must
230be included directly:
231
232```html
233<!-- international support from js-codepage -->
234<script src="dist/cpexcel.js"></script>
235```
236
237An appropriate version for each dependency is included in the dist/ directory.
238
239The complete single-file version is generated at `dist/xlsx.full.min.js`
240
241Webpack and Browserify builds include optional modules by default. Webpack can
242be configured to remove support with `resolve.alias`:
243
244```js
245 /* uncomment the lines below to remove support */
246 resolve: {
247 alias: { "./dist/cpexcel.js": "" } // <-- omit international support
248 }
249```
250
251</details>
252
253### ECMAScript 5 Compatibility
254
255Since the library uses functions like `Array#forEach`, older browsers require
256[shims to provide missing functions](http://oss.sheetjs.com/js-xlsx/shim.js).
257
258To use the shim, add the shim before the script tag that loads `xlsx.js`:
259
260```html
261<!-- add the shim first -->
262<script type="text/javascript" src="shim.min.js"></script>
263<!-- after the shim is referenced, add the library -->
264<script type="text/javascript" src="xlsx.full.min.js"></script>
265```
266
267The script also includes `IE_LoadFile` and `IE_SaveFile` for loading and saving
268files in Internet Explorer versions 6-9. The `xlsx.extendscript.js` script
269bundles the shim in a format suitable for Photoshop and other Adobe products.
270
271## Philosophy
272
273<details>
274 <summary><b>Philosophy</b> (click to show)</summary>
275
276Prior to SheetJS, APIs for processing spreadsheet files were format-specific.
277Third-party libraries either supported one format, or they involved a separate
278set of classes for each supported file type. Even though XLSB was introduced in
279Excel 2007, nothing outside of SheetJS or Excel supported the format.
280
281To promote a format-agnostic view, js-xlsx starts from a pure-JS representation
282that we call the ["Common Spreadsheet Format"](#common-spreadsheet-format).
283Emphasizing a uniform object representation enables new features like format
284conversion (reading an XLSX template and saving as XLS) and circumvents the
285"class trap". By abstracting the complexities of the various formats, tools
286need not worry about the specific file type!
287
288A simple object representation combined with careful coding practices enables
289use cases in older browsers and in alternative environments like ExtendScript
290and Web Workers. It is always tempting to use the latest and greatest features,
291but they tend to require the latest versions of browsers, limiting usability.
292
293Utility functions capture common use cases like generating JS objects or HTML.
294Most simple operations should only require a few lines of code. More complex
295operations generally should be straightforward to implement.
296
297Excel pushes the XLSX format as default starting in Excel 2007. However, there
298are other formats with more appealing properties. For example, the XLSB format
299is spiritually similar to XLSX but files often tend up taking less than half the
300space and open much faster! Even though an XLSX writer is available, other
301format writers are available so users can take advantage of the unique
302characteristics of each format.
303
304The primary focus of the Community Edition is correct data interchange, focused
305on extracting data from any compatible data representation and exporting data in
306various formats suitable for any third party interface.
307
308</details>
309
310## Parsing Workbooks
311
312For parsing, the first step is to read the file. This involves acquiring the
313data and feeding it into the library. Here are a few common scenarios:
314
315<details>
316 <summary><b>nodejs read a file</b> (click to show)</summary>
317
318`readFile` is only available in server environments. Browsers have no API for
319reading arbitrary files given a path, so another strategy must be used.
320
321```js
322if(typeof require !== 'undefined') XLSX = require('xlsx');
323var workbook = XLSX.readFile('test.xlsx');
324/* DO SOMETHING WITH workbook HERE */
325```
326
327</details>
328
329<details>
330 <summary><b>Photoshop ExtendScript read a file</b> (click to show)</summary>
331
332`readFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
333The specified path should be an absolute path:
334
335```js
336#include "xlsx.extendscript.js"
337/* Read test.xlsx from the Documents folder */
338var workbook = XLSX.readFile(Folder.myDocuments + '/' + 'test.xlsx');
339/* DO SOMETHING WITH workbook HERE */
340```
341
342The [`extendscript` demo](demos/extendscript/) includes a more complex example.
343
344</details>
345
346<details>
347 <summary><b>Browser read TABLE element from page</b> (click to show)</summary>
348
349The `table_to_book` and `table_to_sheet` utility functions take a DOM TABLE
350element and iterate through the child nodes.
351
352```js
353var workbook = XLSX.utils.table_to_book(document.getElementById('tableau'));
354/* DO SOMETHING WITH workbook HERE */
355```
356
357Multiple tables on a web page can be converted to individual worksheets:
358
359```js
360/* create new workbook */
361var workbook = XLSX.utils.book_new();
362
363/* convert table 'table1' to worksheet named "Sheet1" */
364var ws1 = XLSX.utils.table_to_sheet(document.getElementById('table1'));
365XLSX.utils.book_append_sheet(workbook, ws1, "Sheet1");
366
367/* convert table 'table2' to worksheet named "Sheet2" */
368var ws2 = XLSX.utils.table_to_sheet(document.getElementById('table2'));
369XLSX.utils.book_append_sheet(workbook, ws2, "Sheet2");
370
371/* workbook now has 2 worksheets */
372```
373
374Alternatively, the HTML code can be extracted and parsed:
375
376```js
377var htmlstr = document.getElementById('tableau').outerHTML;
378var workbook = XLSX.read(htmlstr, {type:'string'});
379```
380
381</details>
382
383<details>
384 <summary><b>Browser download file (ajax)</b> (click to show)</summary>
385
386Note: for a more complete example that works in older browsers, check the demo
387at <http://oss.sheetjs.com/js-xlsx/ajax.html>. The [`xhr` demo](demos/xhr/)
388includes more examples with `XMLHttpRequest` and `fetch`.
389
390```js
391var url = "http://oss.sheetjs.com/test_files/formula_stress_test.xlsx";
392
393/* set up async GET request */
394var req = new XMLHttpRequest();
395req.open("GET", url, true);
396req.responseType = "arraybuffer";
397
398req.onload = function(e) {
399 var data = new Uint8Array(req.response);
400 var workbook = XLSX.read(data, {type:"array"});
401
402 /* DO SOMETHING WITH workbook HERE */
403}
404
405req.send();
406```
407
408</details>
409
410<details>
411 <summary><b>Browser drag-and-drop</b> (click to show)</summary>
412
413Drag-and-drop uses the HTML5 `FileReader` API.
414
415```js
416function handleDrop(e) {
417 e.stopPropagation(); e.preventDefault();
418 var files = e.dataTransfer.files, f = files[0];
419 var reader = new FileReader();
420 reader.onload = function(e) {
421 var data = new Uint8Array(e.target.result);
422 var workbook = XLSX.read(data, {type: 'array'});
423
424 /* DO SOMETHING WITH workbook HERE */
425 };
426 reader.readAsArrayBuffer(f);
427}
428drop_dom_element.addEventListener('drop', handleDrop, false);
429```
430
431</details>
432
433<details>
434 <summary><b>Browser file upload form element</b> (click to show)</summary>
435
436Data from file input elements can be processed using the same `FileReader` API
437as in the drag-and-drop example:
438
439```js
440function handleFile(e) {
441 var files = e.target.files, f = files[0];
442 var reader = new FileReader();
443 reader.onload = function(e) {
444 var data = new Uint8Array(e.target.result);
445 var workbook = XLSX.read(data, {type: 'array'});
446
447 /* DO SOMETHING WITH workbook HERE */
448 };
449 reader.readAsArrayBuffer(f);
450}
451input_dom_element.addEventListener('change', handleFile, false);
452```
453
454The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
455
456</details>
457
458More specialized cases, including mobile app file processing, are covered in the
459[included demos](demos/)
460
461### Parsing Examples
462
463- <http://oss.sheetjs.com/js-xlsx/> HTML5 File API / Base64 Text / Web Workers
464
465Note that older versions of IE do not support HTML5 File API, so the Base64 mode
466is used for testing.
467
468<details>
469 <summary><b>Get Base64 encoding on OSX / Windows</b> (click to show)</summary>
470
471On OSX you can get the Base64 encoding with:
472
473```bash
474$ <target_file base64 | pbcopy
475```
476
477On Windows XP and up you can get the Base64 encoding using `certutil`:
478
479```cmd
480> certutil -encode target_file target_file.b64
481```
482
483(note: You have to open the file and remove the header and footer lines)
484
485</details>
486
487- <http://oss.sheetjs.com/js-xlsx/ajax.html> XMLHttpRequest
488
489### Streaming Read
490
491<details>
492 <summary><b>Why is there no Streaming Read API?</b> (click to show)</summary>
493
494The most common and interesting formats (XLS, XLSX/M, XLSB, ODS) are ultimately
495ZIP or CFB containers of files. Neither format puts the directory structure at
496the beginning of the file: ZIP files place the Central Directory records at the
497end of the logical file, while CFB files can place the storage info anywhere in
498the file! As a result, to properly handle these formats, a streaming function
499would have to buffer the entire file before commencing. That belies the
500expectations of streaming, so we do not provide any streaming read API.
501
502</details>
503
504When dealing with Readable Streams, the easiest approach is to buffer the stream
505and process the whole thing at the end. This can be done with a temporary file
506or by explicitly concatenating the stream:
507
508<details>
509 <summary><b>Explicitly concatenating streams</b> (click to show)</summary>
510
511```js
512var fs = require('fs');
513var XLSX = require('xlsx');
514function process_RS(stream/*:ReadStream*/, cb/*:(wb:Workbook)=>void*/)/*:void*/{
515 var buffers = [];
516 stream.on('data', function(data) { buffers.push(data); });
517 stream.on('end', function() {
518 var buffer = Buffer.concat(buffers);
519 var workbook = XLSX.read(buffer, {type:"buffer"});
520
521 /* DO SOMETHING WITH workbook IN THE CALLBACK */
522 cb(workbook);
523 });
524}
525```
526
527More robust solutions are available using modules like `concat-stream`.
528
529</details>
530
531<details>
532 <summary><b>Writing to filesystem first</b> (click to show)</summary>
533
534This example uses [`tempfile`](https://npm.im/tempfile) to generate file names:
535
536```js
537var fs = require('fs'), tempfile = require('tempfile');
538var XLSX = require('xlsx');
539function process_RS(stream/*:ReadStream*/, cb/*:(wb:Workbook)=>void*/)/*:void*/{
540 var fname = tempfile('.sheetjs');
541 console.log(fname);
542 var ostream = fs.createWriteStream(fname);
543 stream.pipe(ostream);
544 ostream.on('finish', function() {
545 var workbook = XLSX.readFile(fname);
546 fs.unlinkSync(fname);
547
548 /* DO SOMETHING WITH workbook IN THE CALLBACK */
549 cb(workbook);
550 });
551}
552```
553
554</details>
555
556## Working with the Workbook
557
558The full object format is described later in this README.
559
560<details>
561 <summary><b>Reading a specific cell </b> (click to show)</summary>
562
563This example extracts the value stored in cell A1 from the first worksheet:
564
565```js
566var first_sheet_name = workbook.SheetNames[0];
567var address_of_cell = 'A1';
568
569/* Get worksheet */
570var worksheet = workbook.Sheets[first_sheet_name];
571
572/* Find desired cell */
573var desired_cell = worksheet[address_of_cell];
574
575/* Get the value */
576var desired_value = (desired_cell ? desired_cell.v : undefined);
577```
578
579</details>
580
581<details>
582 <summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary>
583
584This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
585sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
586
587```js
588var new_ws_name = "SheetJS";
589
590/* make worksheet */
591var ws_data = [
592 [ "S", "h", "e", "e", "t", "J", "S" ],
593 [ 1 , 2 , 3 , 4 , 5 ]
594];
595var ws = XLSX.utils.aoa_to_sheet(ws_data);
596
597/* Add the worksheet to the workbook */
598XLSX.utils.book_append_sheet(wb, ws, ws_name);
599```
600
601</details>
602
603<details>
604 <summary><b>Creating a new workbook from scratch</b> (click to show)</summary>
605
606The workbook object contains a `SheetNames` array of names and a `Sheets` object
607mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
608creates a new workbook object:
609
610```js
611/* create a new blank workbook */
612var wb = XLSX.utils.book_new();
613```
614
615The new workbook is blank and contains no worksheets. The write functions will
616error if the workbook is empty.
617
618</details>
619
620
621### Parsing and Writing Examples
622
623- <http://sheetjs.com/demos/modify.html> read + modify + write files
624
625- <https://github.com/SheetJS/js-xlsx/blob/master/bin/xlsx.njs> node
626
627The node version installs a command line tool `xlsx` which can read spreadsheet
628files and output the contents in various formats. The source is available at
629`xlsx.njs` in the bin directory.
630
631Some helper functions in `XLSX.utils` generate different views of the sheets:
632
633- `XLSX.utils.sheet_to_csv` generates CSV
634- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
635- `XLSX.utils.sheet_to_html` generates HTML
636- `XLSX.utils.sheet_to_json` generates an array of objects
637- `XLSX.utils.sheet_to_formulae` generates a list of formulae
638
639## Writing Workbooks
640
641For writing, the first step is to generate output data. The helper functions
642`write` and `writeFile` will produce the data in various formats suitable for
643dissemination. The second step is to actual share the data with the end point.
644Assuming `workbook` is a workbook object:
645
646<details>
647 <summary><b>nodejs write a file</b> (click to show)</summary>
648
649`XLSX.writeFile` uses `fs.writeFileSync` in server environments:
650
651```js
652if(typeof require !== 'undefined') XLSX = require('xlsx');
653/* output format determined by filename */
654XLSX.writeFile(workbook, 'out.xlsb');
655/* at this point, out.xlsb is a file that you can distribute */
656```
657
658</details>
659
660<details>
661 <summary><b>Photoshop ExtendScript write a file</b> (click to show)</summary>
662
663`writeFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
664The specified path should be an absolute path:
665
666```js
667#include "xlsx.extendscript.js"
668/* output format determined by filename */
669XLSX.writeFile(workbook, 'out.xlsx');
670/* at this point, out.xlsx is a file that you can distribute */
671```
672
673The [`extendscript` demo](demos/extendscript/) includes a more complex example.
674
675</details>
676
677<details>
678 <summary><b>Browser add TABLE element to page</b> (click to show)</summary>
679
680The `sheet_to_html` utility function generates HTML code that can be added to
681any DOM element.
682
683```js
684var worksheet = workbook.Sheets[workbook.SheetNames[0]];
685var container = document.getElementById('tableau');
686container.innerHTML = XLSX.utils.sheet_to_html(worksheet);
687```
688
689</details>
690
691<details>
692 <summary><b>Browser upload file (ajax)</b> (click to show)</summary>
693
694A complete example using XHR is [included in the XHR demo](demos/xhr/), along
695with examples for fetch and wrapper libraries. This example assumes the server
696can handle Base64-encoded files (see the demo for a basic nodejs server):
697
698```js
699/* in this example, send a base64 string to the server */
700var wopts = { bookType:'xlsx', bookSST:false, type:'base64' };
701
702var wbout = XLSX.write(workbook,wopts);
703
704var req = new XMLHttpRequest();
705req.open("POST", "/upload", true);
706var formdata = new FormData();
707formdata.append('file', 'test.xlsx'); // <-- server expects `file` to hold name
708formdata.append('data', wbout); // <-- `data` holds the base64-encoded data
709req.send(formdata);
710```
711
712</details>
713
714<details>
715 <summary><b>Browser save file</b> (click to show)</summary>
716
717`XLSX.writeFile` wraps a few techniques for triggering a file save:
718
719- `URL` browser API creates an object URL for the file, which the library uses
720 by creating a link and forcing a click. It is supported in modern browsers.
721- `msSaveBlob` is an IE10+ API for triggering a file save.
722- `IE_FileSave` uses VBScript and ActiveX to write a file in IE6+ for Windows
723 XP and Windows 7. The shim must be included in the containing HTML page.
724
725There is no standard way to determine if the actual file has been downloaded.
726
727```js
728/* output format determined by filename */
729XLSX.writeFile(workbook, 'out.xlsb');
730/* at this point, out.xlsb will have been downloaded */
731```
732
733</details>
734
735<details>
736 <summary><b>Browser save file (compatibility)</b> (click to show)</summary>
737
738`XLSX.writeFile` techniques work for most modern browsers as well as older IE.
739For much older browsers, there are workarounds implemented by wrapper libraries.
740
741[`FileSaver.js`](https://github.com/eligrey/FileSaver.js/) implements `saveAs`.
742Note: `XLSX.writeFile` will automatically call `saveAs` if available.
743
744```js
745/* bookType can be any supported output type */
746var wopts = { bookType:'xlsx', bookSST:false, type:'array' };
747
748var wbout = XLSX.write(workbook,wopts);
749
750/* the saveAs call downloads a file on the local machine */
751saveAs(new Blob([wbout],{type:"application/octet-stream"}), "test.xlsx");
752```
753
754[`Downloadify`](https://github.com/dcneiner/downloadify) uses a Flash SWF button
755to generate local files, suitable for environments where ActiveX is unavailable:
756
757```js
758Downloadify.create(id,{
759 /* other options are required! read the downloadify docs for more info */
760 filename: "test.xlsx",
761 data: function() { return XLSX.write(wb, {bookType:"xlsx", type:'base64'}); },
762 append: false,
763 dataType: 'base64'
764});
765```
766
767The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
768
769</details>
770
771The [included demos](demos/) cover mobile apps and other special deployments.
772
773### Writing Examples
774
775- <http://sheetjs.com/demos/table.html> exporting an HTML table
776- <http://sheetjs.com/demos/writexlsx.html> generates a simple file
777
778### Streaming Write
779
780The streaming write functions are available in the `XLSX.stream` object. They
781take the same arguments as the normal write functions but return a Readable
782Stream. They are only exposed in NodeJS.
783
784- `XLSX.stream.to_csv` is the streaming version of `XLSX.utils.sheet_to_csv`.
785- `XLSX.stream.to_html` is the streaming version of `XLSX.utils.sheet_to_html`.
786- `XLSX.stream.to_json` is the streaming version of `XLSX.utils.sheet_to_json`.
787
788<details>
789 <summary><b>nodejs convert to CSV and write file</b> (click to show)</summary>
790
791```js
792var output_file_name = "out.csv";
793var stream = XLSX.stream.to_csv(worksheet);
794stream.pipe(fs.createWriteStream(output_file_name));
795```
796
797</details>
798
799<details>
800 <summary><b>nodejs write JSON stream to screen</b> (click to show)</summary>
801
802```js
803/* to_json returns an object-mode stream */
804var stream = XLSX.stream.to_json(worksheet, {raw:true});
805
806/* the following stream converts JS objects to text via JSON.stringify */
807var conv = new Transform({writableObjectMode:true});
808conv._transform = function(obj, e, cb){ cb(null, JSON.stringify(obj) + "\n"); };
809
810stream.pipe(conv); conv.pipe(process.stdout);
811```
812
813</details>
814
815<https://github.com/sheetjs/sheetaki> pipes write streams to nodejs response.
816
817## Interface
818
819`XLSX` is the exposed variable in the browser and the exported node variable
820
821`XLSX.version` is the version of the library (added by the build script).
822
823`XLSX.SSF` is an embedded version of the [format library](http://git.io/ssf).
824
825### Parsing functions
826
827`XLSX.read(data, read_opts)` attempts to parse `data`.
828
829`XLSX.readFile(filename, read_opts)` attempts to read `filename` and parse.
830
831Parse options are described in the [Parsing Options](#parsing-options) section.
832
833### Writing functions
834
835`XLSX.write(wb, write_opts)` attempts to write the workbook `wb`
836
837`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`.
838In browser-based environments, it will attempt to force a client-side download.
839
840`XLSX.writeFileAsync(filename, wb, o, cb)` attempts to write `wb` to `filename`.
841If `o` is omitted, the writer will use the third argument as the callback.
842
843`XLSX.stream` contains a set of streaming write functions.
844
845Write options are described in the [Writing Options](#writing-options) section.
846
847### Utilities
848
849Utilities are available in the `XLSX.utils` object and are described in the
850[Utility Functions](#utility-functions) section:
851
852**Importing:**
853
854- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
855- `json_to_sheet` converts an array of JS objects to a worksheet.
856- `table_to_sheet` converts a DOM TABLE element to a worksheet.
857- `sheet_add_aoa` adds an array of arrays of JS data to an existing worksheet.
858- `sheet_add_json` adds an array of JS objects to an existing worksheet.
859
860
861**Exporting:**
862
863- `sheet_to_json` converts a worksheet object to an array of JSON objects.
864- `sheet_to_csv` generates delimiter-separated-values output.
865- `sheet_to_txt` generates UTF16 formatted text.
866- `sheet_to_html` generates HTML output.
867- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
868
869
870**Cell and cell address manipulation:**
871
872- `format_cell` generates the text value for a cell (using number formats).
873- `encode_row / decode_row` converts between 0-indexed rows and 1-indexed rows.
874- `encode_col / decode_col` converts between 0-indexed columns and column names.
875- `encode_cell / decode_cell` converts cell addresses.
876- `encode_range / decode_range` converts cell ranges.
877
878## Common Spreadsheet Format
879
880js-xlsx conforms to the Common Spreadsheet Format (CSF):
881
882### General Structures
883
884Cell address objects are stored as `{c:C, r:R}` where `C` and `R` are 0-indexed
885column and row numbers, respectively. For example, the cell address `B5` is
886represented by the object `{c:1, r:4}`.
887
888Cell range objects are stored as `{s:S, e:E}` where `S` is the first cell and
889`E` is the last cell in the range. The ranges are inclusive. For example, the
890range `A3:B7` is represented by the object `{s:{c:0, r:2}, e:{c:1, r:6}}`.
891Utility functions perform a row-major order walk traversal of a sheet range:
892
893```js
894for(var R = range.s.r; R <= range.e.r; ++R) {
895 for(var C = range.s.c; C <= range.e.c; ++C) {
896 var cell_address = {c:C, r:R};
897 /* if an A1-style address is needed, encode the address */
898 var cell_ref = XLSX.utils.encode_cell(cell_address);
899 }
900}
901```
902
903### Cell Object
904
905Cell objects are plain JS objects with keys and values following the convention:
906
907| Key | Description |
908| --- | ---------------------------------------------------------------------- |
909| `v` | raw value (see Data Types section for more info) |
910| `w` | formatted text (if applicable) |
911| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
912| `f` | cell formula encoded as an A1-style string (if applicable) |
913| `F` | range of enclosing array if formula is array formula (if applicable) |
914| `r` | rich text encoding (if applicable) |
915| `h` | HTML rendering of the rich text (if applicable) |
916| `c` | comments associated with the cell |
917| `z` | number format string associated with the cell (if requested) |
918| `l` | cell hyperlink object (`.Target` holds link, `.Tooltip` is tooltip) |
919| `s` | the style/theme of the cell (if applicable) |
920
921Built-in export utilities (such as the CSV exporter) will use the `w` text if it
922is available. To change a value, be sure to delete `cell.w` (or set it to
923`undefined`) before attempting to export. The utilities will regenerate the `w`
924text from the number format (`cell.z`) and the raw value if possible.
925
926The actual array formula is stored in the `f` field of the first cell in the
927array range. Other cells in the range will omit the `f` field.
928
929#### Data Types
930
931The raw value is stored in the `v` value property, interpreted based on the `t`
932type property. This separation allows for representation of numbers as well as
933numeric text. There are 6 valid cell types:
934
935| Type | Description |
936| :--: | :-------------------------------------------------------------------- |
937| `b` | Boolean: value interpreted as JS `boolean` |
938| `e` | Error: value is a numeric code and `w` property stores common name ** |
939| `n` | Number: value is a JS `number` ** |
940| `d` | Date: value is a JS `Date` object or string to be parsed as Date ** |
941| `s` | Text: value interpreted as JS `string` and written as text ** |
942| `z` | Stub: blank stub cell that is ignored by data processing utilities ** |
943
944<details>
945 <summary><b>Error values and interpretation</b> (click to show)</summary>
946
947| Value | Error Meaning |
948| -----: | :-------------- |
949| `0x00` | `#NULL!` |
950| `0x07` | `#DIV/0!` |
951| `0x0F` | `#VALUE!` |
952| `0x17` | `#REF!` |
953| `0x1D` | `#NAME?` |
954| `0x24` | `#NUM!` |
955| `0x2A` | `#N/A` |
956| `0x2B` | `#GETTING_DATA` |
957
958</details>
959
960Type `n` is the Number type. This includes all forms of data that Excel stores
961as numbers, such as dates/times and Boolean fields. Excel exclusively uses data
962that can be fit in an IEEE754 floating point number, just like JS Number, so the
963`v` field holds the raw number. The `w` field holds formatted text. Dates are
964stored as numbers by default and converted with `XLSX.SSF.parse_date_code`.
965
966Type `d` is the Date type, generated only when the option `cellDates` is passed.
967Since JSON does not have a natural Date type, parsers are generally expected to
968store ISO 8601 Date strings like you would get from `date.toISOString()`. On
969the other hand, writers and exporters should be able to handle date strings and
970JS Date objects. Note that Excel disregards timezone modifiers and treats all
971dates in the local timezone. The library does not correct for this error.
972
973Type `s` is the String type. Values are explicitly stored as text. Excel will
974interpret these cells as "number stored as text". Generated Excel files
975automatically suppress that class of error, but other formats may elicit errors.
976
977Type `z` represents blank stub cells. They are generated in cases where cells
978have no assigned value but hold comments or other metadata. They are ignored by
979the core library data processing utility functions. By default these cells are
980not generated; the parser `sheetStubs` option must be set to `true`.
981
982
983#### Dates
984
985<details>
986 <summary><b>Excel Date Code details</b> (click to show)</summary>
987
988By default, Excel stores dates as numbers with a format code that specifies date
989processing. For example, the date `19-Feb-17` is stored as the number `42785`
990with a number format of `d-mmm-yy`. The `SSF` module understands number formats
991and performs the appropriate conversion.
992
993XLSX also supports a special date type `d` where the data is an ISO 8601 date
994string. The formatter converts the date back to a number.
995
996The default behavior for all parsers is to generate number cells. Setting
997`cellDates` to true will force the generators to store dates.
998
999</details>
1000
1001<details>
1002 <summary><b>Time Zones and Dates</b> (click to show)</summary>
1003
1004Excel has no native concept of universal time. All times are specified in the
1005local time zone. Excel limitations prevent specifying true absolute dates.
1006
1007Following Excel, this library treats all dates as relative to local time zone.
1008
1009</details>
1010
1011<details>
1012 <summary><b>Epochs: 1900 and 1904</b> (click to show)</summary>
1013
1014Excel supports two epochs (January 1 1900 and January 1 1904), see
1015["1900 vs. 1904 Date System" article](http://support2.microsoft.com/kb/180162).
1016The workbook's epoch can be determined by examining the workbook's
1017`wb.Workbook.WBProps.date1904` property:
1018
1019```js
1020!!(((wb.Workbook||{}).WBProps||{}).date1904)
1021```
1022
1023</details>
1024
1025### Sheet Objects
1026
1027Each key that does not start with `!` maps to a cell (using `A-1` notation)
1028
1029`sheet[address]` returns the cell object for the specified address.
1030
1031**Special sheet keys (accessible as `sheet[key]`, each starting with `!`):**
1032
1033- `sheet['!ref']`: A-1 based range representing the sheet range. Functions that
1034 work with sheets should use this parameter to determine the range. Cells that
1035 are assigned outside of the range are not processed. In particular, when
1036 writing a sheet by hand, cells outside of the range are not included
1037
1038 Functions that handle sheets should test for the presence of `!ref` field.
1039 If the `!ref` is omitted or is not a valid range, functions are free to treat
1040 the sheet as empty or attempt to guess the range. The standard utilities that
1041 ship with this library treat sheets as empty (for example, the CSV output is
1042 empty string).
1043
1044 When reading a worksheet with the `sheetRows` property set, the ref parameter
1045 will use the restricted range. The original range is set at `ws['!fullref']`
1046
1047- `sheet['!margins']`: Object representing the page margins. The default values
1048 follow Excel's "normal" preset. Excel also has a "wide" and a "narrow" preset
1049 but they are stored as raw measurements. The main properties are listed below:
1050
1051<details>
1052 <summary><b>Page margin details</b> (click to show)</summary>
1053
1054| key | description | "normal" | "wide" | "narrow" |
1055|----------|------------------------|:---------|:-------|:-------- |
1056| `left` | left margin (inches) | `0.7` | `1.0` | `0.25` |
1057| `right` | right margin (inches) | `0.7` | `1.0` | `0.25` |
1058| `top` | top margin (inches) | `0.75` | `1.0` | `0.75` |
1059| `bottom` | bottom margin (inches) | `0.75` | `1.0` | `0.75` |
1060| `header` | header margin (inches) | `0.3` | `0.5` | `0.3` |
1061| `footer` | footer margin (inches) | `0.3` | `0.5` | `0.3` |
1062
1063```js
1064/* Set worksheet sheet to "normal" */
1065ws["!margins"]={left:0.7, right:0.7, top:0.75,bottom:0.75,header:0.3,footer:0.3}
1066/* Set worksheet sheet to "wide" */
1067ws["!margins"]={left:1.0, right:1.0, top:1.0, bottom:1.0, header:0.5,footer:0.5}
1068/* Set worksheet sheet to "narrow" */
1069ws["!margins"]={left:0.25,right:0.25,top:0.75,bottom:0.75,header:0.3,footer:0.3}
1070```
1071</details>
1072
1073#### Worksheet Object
1074
1075In addition to the base sheet keys, worksheets also add:
1076
1077- `ws['!cols']`: array of column properties objects. Column widths are actually
1078 stored in files in a normalized manner, measured in terms of the "Maximum
1079 Digit Width" (the largest width of the rendered digits 0-9, in pixels). When
1080 parsed, the column objects store the pixel width in the `wpx` field, character
1081 width in the `wch` field, and the maximum digit width in the `MDW` field.
1082
1083- `ws['!rows']`: array of row properties objects as explained later in the docs.
1084 Each row object encodes properties including row height and visibility.
1085
1086- `ws['!merges']`: array of range objects corresponding to the merged cells in
1087 the worksheet. Plain text formats do not support merge cells. CSV export
1088 will write all cells in the merge range if they exist, so be sure that only
1089 the first cell (upper-left) in the range is set.
1090
1091- `ws['!protect']`: object of write sheet protection properties. The `password`
1092 key specifies the password for formats that support password-protected sheets
1093 (XLSX/XLSB/XLS). The writer uses the XOR obfuscation method. The following
1094 keys control the sheet protection -- set to `false` to enable a feature when
1095 sheet is locked or set to `true` to disable a feature:
1096
1097<details>
1098 <summary><b>Worksheet Protection Details</b> (click to show)</summary>
1099
1100| key | feature (true=disabled / false=enabled) | default |
1101|:----------------------|:----------------------------------------|:-----------|
1102| `selectLockedCells` | Select locked cells | enabled |
1103| `selectUnlockedCells` | Select unlocked cells | enabled |
1104| `formatCells` | Format cells | disabled |
1105| `formatColumns` | Format columns | disabled |
1106| `formatRows` | Format rows | disabled |
1107| `insertColumns` | Insert columns | disabled |
1108| `insertRows` | Insert rows | disabled |
1109| `insertHyperlinks` | Insert hyperlinks | disabled |
1110| `deleteColumns` | Delete columns | disabled |
1111| `deleteRows` | Delete rows | disabled |
1112| `sort` | Sort | disabled |
1113| `autoFilter` | Filter | disabled |
1114| `pivotTables` | Use PivotTable reports | disabled |
1115| `objects` | Edit objects | enabled |
1116| `scenarios` | Edit scenarios | enabled |
1117</details>
1118
1119- `ws['!autofilter']`: AutoFilter object following the schema:
1120
1121```typescript
1122type AutoFilter = {
1123 ref:string; // A-1 based range representing the AutoFilter table range
1124}
1125```
1126
1127#### Chartsheet Object
1128
1129Chartsheets are represented as standard sheets. They are distinguished with the
1130`!type` property set to `"chart"`.
1131
1132The underlying data and `!ref` refer to the cached data in the chartsheet. The
1133first row of the chartsheet is the underlying header.
1134
1135#### Macrosheet Object
1136
1137Macrosheets are represented as standard sheets. They are distinguished with the
1138`!type` property set to `"macro"`.
1139
1140#### Dialogsheet Object
1141
1142Dialogsheets are represented as standard sheets. They are distinguished with the
1143`!type` property set to `"dialog"`.
1144
1145### Workbook Object
1146
1147`workbook.SheetNames` is an ordered list of the sheets in the workbook
1148
1149`wb.Sheets[sheetname]` returns an object representing the worksheet.
1150
1151`wb.Props` is an object storing the standard properties. `wb.Custprops` stores
1152custom properties. Since the XLS standard properties deviate from the XLSX
1153standard, XLS parsing stores core properties in both places.
1154
1155`wb.Workbook` stores [workbook-level attributes](#workbook-level-attributes).
1156
1157#### Workbook File Properties
1158
1159The various file formats use different internal names for file properties. The
1160workbook `Props` object normalizes the names:
1161
1162<details>
1163 <summary><b>File Properties</b> (click to show)</summary>
1164
1165| JS Name | Excel Description |
1166|:--------------|:-------------------------------|
1167| `Title` | Summary tab "Title" |
1168| `Subject` | Summary tab "Subject" |
1169| `Author` | Summary tab "Author" |
1170| `Manager` | Summary tab "Manager" |
1171| `Company` | Summary tab "Company" |
1172| `Category` | Summary tab "Category" |
1173| `Keywords` | Summary tab "Keywords" |
1174| `Comments` | Summary tab "Comments" |
1175| `LastAuthor` | Statistics tab "Last saved by" |
1176| `CreatedDate` | Statistics tab "Created" |
1177
1178</details>
1179
1180For example, to set the workbook title property:
1181
1182```js
1183if(!wb.Props) wb.Props = {};
1184wb.Props.Title = "Insert Title Here";
1185```
1186
1187Custom properties are added in the workbook `Custprops` object:
1188
1189```js
1190if(!wb.Custprops) wb.Custprops = {};
1191wb.Custprops["Custom Property"] = "Custom Value";
1192```
1193
1194Writers will process the `Props` key of the options object:
1195
1196```js
1197/* force the Author to be "SheetJS" */
1198XLSX.write(wb, {Props:{Author:"SheetJS"}});
1199```
1200
1201### Workbook-Level Attributes
1202
1203`wb.Workbook` stores workbook-level attributes.
1204
1205#### Defined Names
1206
1207`wb.Workbook.Names` is an array of defined name objects which have the keys:
1208
1209<details>
1210 <summary><b>Defined Name Properties</b> (click to show)</summary>
1211
1212| Key | Description |
1213|:----------|:-----------------------------------------------------------------|
1214| `Sheet` | Name scope. Sheet Index (0 = first sheet) or `null` (Workbook) |
1215| `Name` | Case-sensitive name. Standard rules apply ** |
1216| `Ref` | A1-style Reference (`"Sheet1!$A$1:$D$20"`) |
1217| `Comment` | Comment (only applicable for XLS/XLSX/XLSB) |
1218
1219</details>
1220
1221Excel allows two sheet-scoped defined names to share the same name. However, a
1222sheet-scoped name cannot collide with a workbook-scope name. Workbook writers
1223may not enforce this constraint.
1224
1225#### Workbook Views
1226
1227`wb.Workbook.Views` is an array of workbook view objects which have the keys:
1228
1229| Key | Description |
1230|:----------------|:----------------------------------------------------|
1231| `RTL` | If true, display right-to-left |
1232
1233#### Miscellaneous Workbook Properties
1234
1235`wb.Workbook.WBProps` holds other workbook properties:
1236
1237| Key | Description |
1238|:----------------|:----------------------------------------------------|
1239| `CodeName` | [VBA Project Workbook Code Name](#vba-and-macros) |
1240| `date1904` | epoch: 0/false for 1900 system, 1/true for 1904 |
1241| `filterPrivacy` | Warn or strip personally identifying info on save |
1242
1243### Document Features
1244
1245Even for basic features like date storage, the official Excel formats store the
1246same content in different ways. The parsers are expected to convert from the
1247underlying file format representation to the Common Spreadsheet Format. Writers
1248are expected to convert from CSF back to the underlying file format.
1249
1250#### Formulae
1251
1252The A1-style formula string is stored in the `f` field. Even though different
1253file formats store the formulae in different ways, the formats are translated.
1254Even though some formats store formulae with a leading equal sign, CSF formulae
1255do not start with `=`.
1256
1257<details>
1258 <summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary>
1259
1260```js
1261{
1262 "!ref": "A1:A3",
1263 A1: { t:'n', v:1 },
1264 A2: { t:'n', v:2 },
1265 A3: { t:'n', v:3, f:'A1+A2' }
1266}
1267```
1268</details>
1269
1270Shared formulae are decompressed and each cell has the formula corresponding to
1271its cell. Writers generally do not attempt to generate shared formulae.
1272
1273Cells with formula entries but no value will be serialized in a way that Excel
1274and other spreadsheet tools will recognize. This library will not automatically
1275compute formula results! For example, to compute `BESSELJ` in a worksheet:
1276
1277<details>
1278 <summary><b>Formula without known value</b> (click to show)</summary>
1279
1280```js
1281{
1282 "!ref": "A1:A3",
1283 A1: { t:'n', v:3.14159 },
1284 A2: { t:'n', v:2 },
1285 A3: { t:'n', f:'BESSELJ(A1,A2)' }
1286}
1287```
1288</details>
1289
1290**Array Formulae**
1291
1292Array formulae are stored in the top-left cell of the array block. All cells
1293of an array formula have a `F` field corresponding to the range. A single-cell
1294formula can be distinguished from a plain formula by the presence of `F` field.
1295
1296<details>
1297 <summary><b>Array Formula examples</b> (click to show)</summary>
1298
1299For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
1300
1301```js
1302worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
1303```
1304
1305For a multi-cell array formula, every cell has the same array range but only the
1306first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
1307
1308```js
1309worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
1310worksheet['D2'] = { t:'n', F:"D1:D3" };
1311worksheet['D3'] = { t:'n', F:"D1:D3" };
1312```
1313
1314</details>
1315
1316Utilities and writers are expected to check for the presence of a `F` field and
1317ignore any possible formula element `f` in cells other than the starting cell.
1318They are not expected to perform validation of the formulae!
1319
1320<details>
1321 <summary><b>Formula Output Utility Function</b> (click to show)</summary>
1322
1323The `sheet_to_formulae` method generates one line per formula or array formula.
1324Array formulae are rendered in the form `range=formula` while plain cells are
1325rendered in the form `cell=formula or value`. Note that string literals are
1326prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
1327</details>
1328
1329<details>
1330 <summary><b>Formulae File Format Details</b> (click to show)</summary>
1331
1332| Storage Representation | Formats | Read | Write |
1333|:-----------------------|:-------------------------|:-----:|:-----:|
1334| A1-style strings | XLSX | :o: | :o: |
1335| RC-style strings | XLML and plain text | :o: | :o: |
1336| BIFF Parsed formulae | XLSB and all XLS formats | :o: | |
1337| OpenFormula formulae | ODS/FODS/UOS | :o: | :o: |
1338
1339Since Excel prohibits named cells from colliding with names of A1 or RC style
1340cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
1341formulae have to be explicitly unwound. OpenFormula formulae can be converted
1342with regular expressions.
1343</details>
1344
1345#### Column Properties
1346
1347The `!cols` array in each worksheet, if present, is a collection of `ColInfo`
1348objects which have the following properties:
1349
1350```typescript
1351type ColInfo = {
1352 /* visibility */
1353 hidden?: boolean; // if true, the column is hidden
1354
1355 /* column width is specified in one of the following ways: */
1356 wpx?: number; // width in screen pixels
1357 width?: number; // width in Excel's "Max Digit Width", width*256 is integral
1358 wch?: number; // width in characters
1359
1360 /* other fields for preserving features from files */
1361 MDW?: number; // Excel's "Max Digit Width" unit, always integral
1362};
1363```
1364
1365<details>
1366 <summary><b>Why are there three width types?</b> (click to show)</summary>
1367
1368There are three different width types corresponding to the three different ways
1369spreadsheets store column widths:
1370
1371SYLK and other plain text formats use raw character count. Contemporaneous tools
1372like Visicalc and Multiplan were character based. Since the characters had the
1373same width, it sufficed to store a count. This tradition was continued into the
1374BIFF formats.
1375
1376SpreadsheetML (2003) tried to align with HTML by standardizing on screen pixel
1377count throughout the file. Column widths, row heights, and other measures use
1378pixels. When the pixel and character counts do not align, Excel rounds values.
1379
1380XLSX internally stores column widths in a nebulous "Max Digit Width" form. The
1381Max Digit Width is the width of the largest digit when rendered (generally the
1382"0" character is the widest). The internal width must be an integer multiple of
1383the the width divided by 256. ECMA-376 describes a formula for converting
1384between pixels and the internal width. This represents a hybrid approach.
1385
1386Read functions attempt to populate all three properties. Write functions will
1387try to cycle specified values to the desired type. In order to avoid potential
1388conflicts, manipulation should delete the other properties first. For example,
1389when changing the pixel width, delete the `wch` and `width` properties.
1390</details>
1391
1392<details>
1393 <summary><b>Implementation details</b> (click to show)</summary>
1394
1395Given the constraints, it is possible to determine the MDW without actually
1396inspecting the font! The parsers guess the pixel width by converting from width
1397to pixels and back, repeating for all possible MDW and selecting the MDW that
1398minimizes the error. XLML actually stores the pixel width, so the guess works
1399in the opposite direction.
1400
1401Even though all of the information is made available, writers are expected to
1402follow the priority order:
1403
14041) use `width` field if available
14052) use `wpx` pixel width if available
14063) use `wch` character count if available
1407</details>
1408
1409#### Row Properties
1410
1411The `!rows` array in each worksheet, if present, is a collection of `RowInfo`
1412objects which have the following properties:
1413
1414```typescript
1415type RowInfo = {
1416 /* visibility */
1417 hidden?: boolean; // if true, the row is hidden
1418
1419 /* row height is specified in one of the following ways: */
1420 hpx?: number; // height in screen pixels
1421 hpt?: number; // height in points
1422
1423 level?: number; // 0-indexed outline / group level
1424};
1425```
1426
1427Note: Excel UI displays the base outline level as `1` and the max level as `8`.
1428The `level` field stores the base outline as `0` and the max level as `7`.
1429
1430<details>
1431 <summary><b>Implementation details</b> (click to show)</summary>
1432
1433Excel internally stores row heights in points. The default resolution is 72 DPI
1434or 96 PPI, so the pixel and point size should agree. For different resolutions
1435they may not agree, so the library separates the concepts.
1436
1437Even though all of the information is made available, writers are expected to
1438follow the priority order:
1439
14401) use `hpx` pixel height if available
14412) use `hpt` point height if available
1442</details>
1443
1444#### Number Formats
1445
1446The `cell.w` formatted text for each cell is produced from `cell.v` and `cell.z`
1447format. If the format is not specified, the Excel `General` format is used.
1448The format can either be specified as a string or as an index into the format
1449table. Parsers are expected to populate `workbook.SSF` with the number format
1450table. Writers are expected to serialize the table.
1451
1452Custom tools should ensure that the local table has each used format string
1453somewhere in the table. Excel convention mandates that the custom formats start
1454at index 164. The following example creates a custom format from scratch:
1455
1456<details>
1457 <summary><b>New worksheet with custom format</b> (click to show)</summary>
1458
1459```js
1460var wb = {
1461 SheetNames: ["Sheet1"],
1462 Sheets: {
1463 Sheet1: {
1464 "!ref":"A1:C1",
1465 A1: { t:"n", v:10000 }, // <-- General format
1466 B1: { t:"n", v:10000, z: "0%" }, // <-- Builtin format
1467 C1: { t:"n", v:10000, z: "\"T\"\ #0.00" } // <-- Custom format
1468 }
1469 }
1470}
1471```
1472</details>
1473
1474The rules are slightly different from how Excel displays custom number formats.
1475In particular, literal characters must be wrapped in double quotes or preceded
1476by a backslash. For more info, see the Excel documentation article
1477`Create or delete a custom number format` or ECMA-376 18.8.31 (Number Formats)
1478
1479
1480<details>
1481 <summary><b>Default Number Formats</b> (click to show)</summary>
1482
1483The default formats are listed in ECMA-376 18.8.30:
1484
1485| ID | Format |
1486|---:|:---------------------------|
1487| 0 | `General` |
1488| 1 | `0` |
1489| 2 | `0.00` |
1490| 3 | `#,##0` |
1491| 4 | `#,##0.00` |
1492| 9 | `0%` |
1493| 10 | `0.00%` |
1494| 11 | `0.00E+00` |
1495| 12 | `# ?/?` |
1496| 13 | `# ??/??` |
1497| 14 | `m/d/yy` (see below) |
1498| 15 | `d-mmm-yy` |
1499| 16 | `d-mmm` |
1500| 17 | `mmm-yy` |
1501| 18 | `h:mm AM/PM` |
1502| 19 | `h:mm:ss AM/PM` |
1503| 20 | `h:mm` |
1504| 21 | `h:mm:ss` |
1505| 22 | `m/d/yy h:mm` |
1506| 37 | `#,##0 ;(#,##0)` |
1507| 38 | `#,##0 ;[Red](#,##0)` |
1508| 39 | `#,##0.00;(#,##0.00)` |
1509| 40 | `#,##0.00;[Red](#,##0.00)` |
1510| 45 | `mm:ss` |
1511| 46 | `[h]:mm:ss` |
1512| 47 | `mmss.0` |
1513| 48 | `##0.0E+0` |
1514| 49 | `@` |
1515
1516</details>
1517
1518Format 14 (`m/d/yy`) is localized by Excel: even though the file specifies that
1519number format, it will be drawn differently based on system settings. It makes
1520sense when the producer and consumer of files are in the same locale, but that
1521is not always the case over the Internet. To get around this ambiguity, parse
1522functions accept the `dateNF` option to override the interpretation of that
1523specific format string.
1524
1525#### Hyperlinks
1526
1527Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
1528hyperlink object is the target of the link, including the URI fragment. Tooltips
1529are stored in the `Tooltip` field and are displayed when you move your mouse
1530over the text.
1531
1532For example, the following snippet creates a link from cell `A3` to
1533<http://sheetjs.com> with the tip `"Find us @ SheetJS.com!"`:
1534
1535```js
1536ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
1537```
1538
1539Note that Excel does not automatically style hyperlinks -- they will generally
1540be displayed as normal text.
1541
1542Links where the target is a cell or range or defined name in the same workbook
1543("Internal Links") are marked with a leading hash character:
1544
1545```js
1546ws['A2'].l = { Target:"#E2" }; /* link to cell E2 */
1547```
1548
1549#### Cell Comments
1550
1551Cell comments are objects stored in the `c` array of cell objects. The actual
1552contents of the comment are split into blocks based on the comment author. The
1553`a` field of each comment object is the author of the comment and the `t` field
1554is the plain text representation.
1555
1556For example, the following snippet appends a cell comment into cell `A1`:
1557
1558```js
1559if(!ws.A1.c) ws.A1.c = [];
1560ws.A1.c.push({a:"SheetJS", t:"I'm a little comment, short and stout!"});
1561```
1562
1563Note: XLSB enforces a 54 character limit on the Author name. Names longer than
156454 characters may cause issues with other formats.
1565
1566To mark a comment as normally hidden, set the `hidden` property:
1567
1568```js
1569if(!ws.A1.c) ws.A1.c = [];
1570ws.A1.c.push({a:"SheetJS", t:"This comment is visible"});
1571
1572if(!ws.A2.c) ws.A2.c = [];
1573ws.A2.c.hidden = true;
1574ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"});
1575```
1576
1577#### Sheet Visibility
1578
1579Excel enables hiding sheets in the lower tab bar. The sheet data is stored in
1580the file but the UI does not readily make it available. Standard hidden sheets
1581are revealed in the "Unhide" menu. Excel also has "very hidden" sheets which
1582cannot be revealed in the menu. It is only accessible in the VB Editor!
1583
1584The visibility setting is stored in the `Hidden` property of sheet props array.
1585
1586<details>
1587 <summary><b>More details</b> (click to show)</summary>
1588
1589| Value | Definition |
1590|:-----:|:------------|
1591| 0 | Visible |
1592| 1 | Hidden |
1593| 2 | Very Hidden |
1594
1595With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>:
1596
1597```js
1598> wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] })
1599[ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ]
1600```
1601
1602Non-Excel formats do not support the Very Hidden state. The best way to test
1603if a sheet is visible is to check if the `Hidden` property is logical truth:
1604
1605```js
1606> wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] })
1607[ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ]
1608```
1609</details>
1610
1611#### VBA and Macros
1612
1613VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
1614property of the workbook object when the `bookVBA` option is `true`. They are
1615supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The supported format
1616writers automatically insert the data blobs if it is present in the workbook and
1617associate with the worksheet names.
1618
1619<details>
1620 <summary><b>Custom Code Names</b> (click to show)</summary>
1621
1622The workbook code name is stored in `wb.Workbook.WBProps.CodeName`. By default,
1623Excel will write `ThisWorkbook` or a translated phrase like `DieseArbeitsmappe`.
1624Worksheet and Chartsheet code names are in the worksheet properties object at
1625`wb.Workbook.Sheets[i].CodeName`. Macrosheets and Dialogsheets are ignored.
1626
1627The readers and writers preserve the code names, but they have to be manually
1628set when adding a VBA blob to a different workbook.
1629
1630</details>
1631
1632<details>
1633 <summary><b>Macrosheets</b> (click to show)</summary>
1634
1635Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
1636stored automation commands. These are exposed in objects with the `!type`
1637property set to `"macro"`.
1638
1639</details>
1640
1641<details>
1642 <summary><b>Detecting macros in workbooks</b> (click to show)</summary>
1643
1644The `vbaraw` field will only be set if macros are present, so testing is simple:
1645
1646```js
1647function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
1648 if(!!wb.vbaraw) return true;
1649 const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
1650 return sheets.some((ws) => !!ws && ws['!type']=='macro');
1651}
1652```
1653
1654</details>
1655
1656## Parsing Options
1657
1658The exported `read` and `readFile` functions accept an options argument:
1659
1660| Option Name | Default | Description |
1661| :---------- | ------: | :--------------------------------------------------- |
1662|`type` | | Input data encoding (see Input Type below) |
1663|`raw` | false | If true, plain text parsing will not parse values ** |
1664|`codepage` | | If specified, use code page when appropriate ** |
1665|`cellFormula`| true | Save formulae to the .f field |
1666|`cellHTML` | true | Parse rich text and save HTML to the `.h` field |
1667|`cellNF` | false | Save number format string to the `.z` field |
1668|`cellStyles` | false | Save style/theme info to the `.s` field |
1669|`cellText` | true | Generated formatted text to the `.w` field |
1670|`cellDates` | false | Store dates as type `d` (default is `n`) |
1671|`dateNF` | | If specified, use the string for date code 14 ** |
1672|`sheetStubs` | false | Create cell objects of type `z` for stub cells |
1673|`sheetRows` | 0 | If >0, read the first `sheetRows` rows ** |
1674|`bookDeps` | false | If true, parse calculation chains |
1675|`bookFiles` | false | If true, add raw files to book object ** |
1676|`bookProps` | false | If true, only parse enough to get book metadata ** |
1677|`bookSheets` | false | If true, only parse enough to get the sheet names |
1678|`bookVBA` | false | If true, copy VBA blob to `vbaraw` field ** |
1679|`password` | "" | If defined and file is encrypted, use password ** |
1680|`WTF` | false | If true, throw errors on unexpected file features ** |
1681
1682- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
1683- In some cases, sheets may be parsed even if `bookSheets` is false.
1684- Excel aggressively tries to interpret values from CSV and other plain text.
1685 This leads to surprising behavior! The `raw` option suppresses value parsing.
1686- `bookSheets` and `bookProps` combine to give both sets of information
1687- `Deps` will be an empty object if `bookDeps` is false
1688- `bookFiles` behavior depends on file type:
1689 * `keys` array (paths in the ZIP) for ZIP-based formats
1690 * `files` hash (mapping paths to objects representing the files) for ZIP
1691 * `cfb` object for formats using CFB containers
1692- `sheetRows-1` rows will be generated when looking at the JSON object output
1693 (since the header row is counted as a row when parsing the data)
1694- `bookVBA` merely exposes the raw VBA CFB object. It does not parse the data.
1695 XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`. BIFF8 XLS mixes
1696 the VBA entries alongside the core Workbook entry, so the library generates a
1697 new XLSB-compatible blob from the XLS CFB container.
1698- `codepage` is applied to BIFF2 - BIFF5 files without `CodePage` records and to
1699 CSV files without BOM in `type:"binary"`. BIFF8 XLS always defaults to 1200.
1700- Currently only XOR encryption is supported. Unsupported error will be thrown
1701 for files employing other encryption methods.
1702- WTF is mainly for development. By default, the parser will suppress read
1703 errors on single worksheets, allowing you to read from the worksheets that do
1704 parse properly. Setting `WTF:1` forces those errors to be thrown.
1705
1706### Input Type
1707
1708Strings can be interpreted in multiple ways. The `type` parameter for `read`
1709tells the library how to parse the data argument:
1710
1711| `type` | expected input |
1712|------------|-----------------------------------------------------------------|
1713| `"base64"` | string: Base64 encoding of the file |
1714| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
1715| `"string"` | string: JS string (characters interpreted as UTF8) |
1716| `"buffer"` | nodejs Buffer |
1717| `"array"` | array: array of 8-bit unsigned int (byte `n` is `data[n]`) |
1718| `"file"` | string: path of file that will be read (nodejs only) |
1719
1720### Guessing File Type
1721
1722<details>
1723 <summary><b>Implementation Details</b> (click to show)</summary>
1724
1725Excel and other spreadsheet tools read the first few bytes and apply other
1726heuristics to determine a file type. This enables file type punning: renaming
1727files with the `.xls` extension will tell your computer to use Excel to open the
1728file but Excel will know how to handle it. This library applies similar logic:
1729
1730| Byte 0 | Raw File Type | Spreadsheet Types |
1731|:-------|:--------------|:----------------------------------------------------|
1732| `0xD0` | CFB Container | BIFF 5/8 or password-protected XLSX/XLSB or WQ3/QPW |
1733| `0x09` | BIFF Stream | BIFF 2/3/4/5 |
1734| `0x3C` | XML/HTML | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
1735| `0x50` | ZIP Archive | XLSB or XLSX/M or ODS or UOS2 or plain text |
1736| `0x49` | Plain Text | SYLK or plain text |
1737| `0x54` | Plain Text | DIF or plain text |
1738| `0xEF` | UTF8 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
1739| `0xFF` | UTF16 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
1740| `0x00` | Record Stream | Lotus WK\* or Quattro Pro or plain text |
1741| `0x7B` | Plain text | RTF or plain text |
1742| `0x0A` | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
1743| `0x0D` | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
1744| `0x20` | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
1745
1746DBF files are detected based on the first byte as well as the third and fourth
1747bytes (corresponding to month and day of the file date)
1748
1749Plain text format guessing follows the priority order:
1750
1751| Format | Test |
1752|:-------|:--------------------------------------------------------------------|
1753| XML | `<?xml` appears in the first 1024 characters |
1754| HTML | starts with `<` and HTML tags appear in the first 1024 characters * |
1755| XML | starts with `<` |
1756| RTF | starts with `{\rt` |
1757| DSV | starts with `/sep=.$/`, separator is the specified character |
1758| DSV | more unquoted `";"` chars than `"\t"` or `","` in the first 1024 |
1759| TSV | more unquoted `"\t"` chars than `","` chars in the first 1024 |
1760| CSV | one of the first 1024 characters is a comma `","` |
1761| ETH | starts with `socialcalc:version:` |
1762| PRN | (default) |
1763
1764- HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div`
1765
1766</details>
1767
1768<details>
1769 <summary><b>Why are random text files valid?</b> (click to show)</summary>
1770
1771Excel is extremely aggressive in reading files. Adding an XLS extension to any
1772display text file (where the only characters are ANSI display chars) tricks
1773Excel into thinking that the file is potentially a CSV or TSV file, even if it
1774is only one column! This library attempts to replicate that behavior.
1775
1776The best approach is to validate the desired worksheet and ensure it has the
1777expected number of rows or columns. Extracting the range is extremely simple:
1778
1779```js
1780var range = XLSX.utils.decode_range(worksheet['!ref']);
1781var ncols = range.e.c - range.s.c + 1, nrows = range.e.r - range.s.r + 1;
1782```
1783
1784</details>
1785
1786## Writing Options
1787
1788The exported `write` and `writeFile` functions accept an options argument:
1789
1790| Option Name | Default | Description |
1791| :---------- | -------: | :-------------------------------------------------- |
1792|`type` | | Output data encoding (see Output Type below) |
1793|`cellDates` | `false` | Store dates as type `d` (default is `n`) |
1794|`bookSST` | `false` | Generate Shared String Table ** |
1795|`bookType` | `"xlsx"` | Type of Workbook (see below for supported formats) |
1796|`sheet` | `""` | Name of Worksheet for single-sheet formats ** |
1797|`compression`| `false` | Use ZIP compression for ZIP-based formats ** |
1798|`Props` | | Override workbook properties when writing ** |
1799|`themeXLSX` | | Override theme XML when writing XLSX/XLSB/XLSM ** |
1800|`ignoreEC` | `true` | Suppress "number as text" errors ** |
1801
1802- `bookSST` is slower and more memory intensive, but has better compatibility
1803 with older versions of iOS Numbers
1804- The raw data is the only thing guaranteed to be saved. Features not described
1805 in this README may not be serialized.
1806- `cellDates` only applies to XLSX output and is not guaranteed to work with
1807 third-party readers. Excel itself does not usually write cells with type `d`
1808 so non-Excel tools may ignore the data or error in the presence of dates.
1809- `Props` is an object mirroring the workbook `Props` field. See the table from
1810 the [Workbook File Properties](#workbook-file-properties) section.
1811- if specified, the string from `themeXLSX` will be saved as the primary theme
1812 for XLSX/XLSB/XLSM files (to `xl/theme/theme1.xml` in the ZIP)
1813- Due to a bug in the program, some features like "Text to Columns" will crash
1814 Excel on worksheets where error conditions are ignored. The writer will mark
1815 files to ignore the error by default. Set `ignoreEC` to `false` to suppress.
1816
1817### Supported Output Formats
1818
1819For broad compatibility with third-party tools, this library supports many
1820output formats. The specific file type is controlled with `bookType` option:
1821
1822| `bookType` | file ext | container | sheets | Description |
1823| :--------- | -------: | :-------: | :----- |:------------------------------- |
1824| `xlsx` | `.xlsx` | ZIP | multi | Excel 2007+ XML Format |
1825| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
1826| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
1827| `biff8` | `.xls` | CFB | multi | Excel 97-2004 Workbook Format |
1828| `biff5` | `.xls` | CFB | multi | Excel 5.0/95 Workbook Format |
1829| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
1830| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
1831| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
1832| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
1833| `csv` | `.csv` | none | single | Comma Separated Values |
1834| `txt` | `.txt` | none | single | UTF-16 Unicode Text (TXT) |
1835| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
1836| `html` | `.html` | none | single | HTML Document |
1837| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
1838| `dbf` | `.dbf` | none | single | dBASE II + VFP Extensions (DBF) |
1839| `rtf` | `.rtf` | none | single | Rich Text Format (RTF) |
1840| `prn` | `.prn` | none | single | Lotus Formatted Text |
1841| `eth` | `.eth` | none | single | Ethercalc Record Format (ETH) |
1842
1843- `compression` only applies to formats with ZIP containers.
1844- Formats that only support a single sheet require a `sheet` option specifying
1845 the worksheet. If the string is empty, the first worksheet is used.
1846- `writeFile` will automatically guess the output file format based on the file
1847 extension if `bookType` is not specified. It will choose the first format in
1848 the aforementioned table that matches the extension.
1849
1850### Output Type
1851
1852The `type` argument for `write` mirrors the `type` argument for `read`:
1853
1854| `type` | output |
1855|------------|-----------------------------------------------------------------|
1856| `"base64"` | string: Base64 encoding of the file |
1857| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
1858| `"string"` | string: JS string (characters interpreted as UTF8) |
1859| `"buffer"` | nodejs Buffer |
1860| `"array"` | ArrayBuffer, fallback array of 8-bit unsigned int |
1861| `"file"` | string: path of file that will be created (nodejs only) |
1862
1863## Utility Functions
1864
1865The `sheet_to_*` functions accept a worksheet and an optional options object.
1866
1867The `*_to_sheet` functions accept a data object and an optional options object.
1868
1869The examples are based on the following worksheet:
1870
1871```
1872XXX| A | B | C | D | E | F | G |
1873---+---+---+---+---+---+---+---+
1874 1 | S | h | e | e | t | J | S |
1875 2 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1876 3 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1877```
1878
1879### Array of Arrays Input
1880
1881`XLSX.utils.aoa_to_sheet` takes an array of arrays of JS values and returns a
1882worksheet resembling the input data. Numbers, Booleans and Strings are stored
1883as the corresponding styles. Dates are stored as date or numbers. Array holes
1884and explicit `undefined` values are skipped. `null` values may be stubbed. All
1885other values are stored as strings. The function takes an options argument:
1886
1887| Option Name | Default | Description |
1888| :---------- | :------: | :-------------------------------------------------- |
1889|`dateNF` | FMT 14 | Use specified date format in string output |
1890|`cellDates` | false | Store dates as type `d` (default is `n`) |
1891|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
1892
1893<details>
1894 <summary><b>Examples</b> (click to show)</summary>
1895
1896To generate the example sheet:
1897
1898```js
1899var ws = XLSX.utils.aoa_to_sheet([
1900 "SheetJS".split(""),
1901 [1,2,3,4,5,6,7],
1902 [2,3,4,5,6,7,8]
1903]);
1904```
1905</details>
1906
1907`XLSX.utils.sheet_add_aoa` takes an array of arrays of JS values and updates an
1908existing worksheet object. It follows the same process as `aoa_to_sheet` and
1909accepts an options argument:
1910
1911| Option Name | Default | Description |
1912| :---------- | :------: | :-------------------------------------------------- |
1913|`dateNF` | FMT 14 | Use specified date format in string output |
1914|`cellDates` | false | Store dates as type `d` (default is `n`) |
1915|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
1916|`origin` | | Use specified cell as starting point (see below) |
1917
1918`origin` is expected to be one of:
1919
1920| `origin` | Description |
1921| :--------------- | :-------------------------------------------------------- |
1922| (cell object) | Use specified cell (cell object) |
1923| (string) | Use specified cell (A1-style cell) |
1924| (number >= 0) | Start from the first column at specified row (0-indexed) |
1925| -1 | Append to bottom of worksheet starting on first column |
1926| (default) | Start from cell A1 |
1927
1928
1929<details>
1930 <summary><b>Examples</b> (click to show)</summary>
1931
1932Consider the worksheet:
1933
1934```
1935XXX| A | B | C | D | E | F | G |
1936---+---+---+---+---+---+---+---+
1937 1 | S | h | e | e | t | J | S |
1938 2 | 1 | 2 | | | 5 | 6 | 7 |
1939 3 | 2 | 3 | | | 6 | 7 | 8 |
1940 4 | 3 | 4 | | | 7 | 8 | 9 |
1941 5 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
1942```
1943
1944This worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
1945
1946```js
1947/* Initial row */
1948var ws = XLSX.utils.aoa_to_sheet([ "SheetJS".split("") ]);
1949
1950/* Write data starting at A2 */
1951XLSX.utils.sheet_add_aoa(ws, [[1,2], [2,3], [3,4]], {origin: "A2"});
1952
1953/* Write data starting at E2 */
1954XLSX.utils.sheet_add_aoa(ws, [[5,6,7], [6,7,8], [7,8,9]], {origin:{r:1, c:4}});
1955
1956/* Append row */
1957XLSX.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
1958```
1959
1960</details>
1961
1962### Array of Objects Input
1963
1964`XLSX.utils.json_to_sheet` takes an array of objects and returns a worksheet
1965with automatically-generated "headers" based on the keys of the objects. The
1966default column order is determined by the first appearance of the field using
1967`Object.keys`, but can be overridden using the options argument:
1968
1969| Option Name | Default | Description |
1970| :---------- | :------: | :-------------------------------------------------- |
1971|`header` | | Use specified column order (default `Object.keys`) |
1972|`dateNF` | FMT 14 | Use specified date format in string output |
1973|`cellDates` | false | Store dates as type `d` (default is `n`) |
1974|`skipHeader` | false | If true, do not include header row in output |
1975
1976<details>
1977 <summary><b>Examples</b> (click to show)</summary>
1978
1979The original sheet cannot be reproduced in the obvious way since JS object keys
1980must be unique. After replacing the second `e` and `S` with `e_1` and `S_1`:
1981
1982```js
1983var ws = XLSX.utils.json_to_sheet([
1984 { S:1, h:2, e:3, e_1:4, t:5, J:6, S_1:7 },
1985 { S:2, h:3, e:4, e_1:5, t:6, J:7, S_1:8 }
1986], {header:["S","h","e","e_1","t","J","S_1"]});
1987```
1988
1989Alternatively, the header row can be skipped:
1990
1991```js
1992var ws = XLSX.utils.json_to_sheet([
1993 { A:"S", B:"h", C:"e", D:"e", E:"t", F:"J", G:"S" },
1994 { A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7 },
1995 { A: 2, B: 3, C: 4, D: 5, E: 6, F: 7, G: 8 }
1996], {header:["A","B","C","D","E","F","G"], skipHeader:true});
1997```
1998
1999</details>
2000
2001`XLSX.utils.sheet_add_json` takes an array of objects and updates an existing
2002worksheet object. It follows the same process as `json_to_sheet` and accepts
2003an options argument:
2004
2005| Option Name | Default | Description |
2006| :---------- | :------: | :-------------------------------------------------- |
2007|`header` | | Use specified column order (default `Object.keys`) |
2008|`dateNF` | FMT 14 | Use specified date format in string output |
2009|`cellDates` | false | Store dates as type `d` (default is `n`) |
2010|`skipHeader` | false | If true, do not include header row in output |
2011|`origin` | | Use specified cell as starting point (see below) |
2012
2013`origin` is expected to be one of:
2014
2015| `origin` | Description |
2016| :--------------- | :-------------------------------------------------------- |
2017| (cell object) | Use specified cell (cell object) |
2018| (string) | Use specified cell (A1-style cell) |
2019| (number >= 0) | Start from the first column at specified row (0-indexed) |
2020| -1 | Append to bottom of worksheet starting on first column |
2021| (default) | Start from cell A1 |
2022
2023
2024<details>
2025 <summary><b>Examples</b> (click to show)</summary>
2026
2027Consider the worksheet:
2028
2029```
2030XXX| A | B | C | D | E | F | G |
2031---+---+---+---+---+---+---+---+
2032 1 | S | h | e | e | t | J | S |
2033 2 | 1 | 2 | | | 5 | 6 | 7 |
2034 3 | 2 | 3 | | | 6 | 7 | 8 |
2035 4 | 3 | 4 | | | 7 | 8 | 9 |
2036 5 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
2037```
2038
2039This worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
2040
2041```js
2042/* Initial row */
2043var ws = XLSX.utils.json_to_sheet([
2044 { A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" }
2045], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true});
2046
2047/* Write data starting at A2 */
2048XLSX.utils.sheet_add_json(ws, [
2049 { A: 1, B: 2 }, { A: 2, B: 3 }, { A: 3, B: 4 }
2050], {skipHeader: true, origin: "A2"});
2051
2052/* Write data starting at E2 */
2053XLSX.utils.sheet_add_json(ws, [
2054 { A: 5, B: 6, C: 7 }, { A: 6, B: 7, C: 8 }, { A: 7, B: 8, C: 9 }
2055], {skipHeader: true, origin: { r: 1, c: 4 }, header: [ "A", "B", "C" ]});
2056
2057/* Append row */
2058XLSX.utils.sheet_add_json(ws, [
2059 { A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 }
2060], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true, origin: -1});
2061```
2062
2063</details>
2064
2065### HTML Table Input
2066
2067`XLSX.utils.table_to_sheet` takes a table DOM element and returns a worksheet
2068resembling the input table. Numbers are parsed. All other data will be stored
2069as strings.
2070
2071`XLSX.utils.table_to_book` produces a minimal workbook based on the worksheet.
2072
2073Both functions accept options arguments:
2074
2075| Option Name | Default | Description |
2076| :---------- | :------: | :-------------------------------------------------- |
2077|`raw` | | If true, every cell will hold raw strings |
2078|`dateNF` | FMT 14 | Use specified date format in string output |
2079|`cellDates` | false | Store dates as type `d` (default is `n`) |
2080|`sheetRows` | 0 | If >0, read the first `sheetRows` rows of the table |
2081|`display` | false | If true, hidden rows and cells will not be parsed |
2082
2083
2084<details>
2085 <summary><b>Examples</b> (click to show)</summary>
2086
2087To generate the example sheet, start with the HTML table:
2088
2089```html
2090<table id="sheetjs">
2091<tr><td>S</td><td>h</td><td>e</td><td>e</td><td>t</td><td>J</td><td>S</td></tr>
2092<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
2093<tr><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td></tr>
2094</table>
2095```
2096
2097To process the table:
2098
2099```js
2100var tbl = document.getElementById('sheetjs');
2101var wb = XLSX.utils.table_to_book(tbl);
2102```
2103</details>
2104
2105Note: `XLSX.read` can handle HTML represented as strings.
2106
2107### Formulae Output
2108
2109`XLSX.utils.sheet_to_formulae` generates an array of commands that represent
2110how a person would enter data into an application. Each entry is of the form
2111`A1-cell-address=formula-or-value`. String literals are prefixed with a `'` in
2112accordance with Excel.
2113
2114<details>
2115 <summary><b>Examples</b> (click to show)</summary>
2116
2117For the example sheet:
2118
2119```js
2120> var o = XLSX.utils.sheet_to_formulae(ws);
2121> [o[0], o[5], o[10], o[15], o[20]];
2122[ 'A1=\'S', 'F1=\'J', 'D2=4', 'B3=3', 'G3=8' ]
2123```
2124</details>
2125
2126### Delimiter-Separated Output
2127
2128As an alternative to the `writeFile` CSV type, `XLSX.utils.sheet_to_csv` also
2129produces CSV output. The function takes an options argument:
2130
2131| Option Name | Default | Description |
2132| :---------- | :------: | :-------------------------------------------------- |
2133|`FS` | `","` | "Field Separator" delimiter between fields |
2134|`RS` | `"\n"` | "Record Separator" delimiter between rows |
2135|`dateNF` | FMT 14 | Use specified date format in string output |
2136|`strip` | false | Remove trailing field separators in each record ** |
2137|`blankrows` | true | Include blank lines in the CSV output |
2138|`skipHidden` | false | Skips hidden rows/columns in the CSV output |
2139
2140- `strip` will remove trailing commas from each line under default `FS/RS`
2141- `blankrows` must be set to `false` to skip blank lines.
2142
2143<details>
2144 <summary><b>Examples</b> (click to show)</summary>
2145
2146For the example sheet:
2147
2148```js
2149> console.log(XLSX.utils.sheet_to_csv(ws));
2150S,h,e,e,t,J,S
21511,2,3,4,5,6,7
21522,3,4,5,6,7,8
2153> console.log(XLSX.utils.sheet_to_csv(ws, {FS:"\t"}));
2154S h e e t J S
21551 2 3 4 5 6 7
21562 3 4 5 6 7 8
2157> console.log(XLSX.utils.sheet_to_csv(ws,{FS:":",RS:"|"}));
2158S:h:e:e:t:J:S|1:2:3:4:5:6:7|2:3:4:5:6:7:8|
2159```
2160</details>
2161
2162#### UTF-16 Unicode Text
2163
2164The `txt` output type uses the tab character as the field separator. If the
2165`codepage` library is available (included in full distribution but not core),
2166the output will be encoded in `CP1200` and the BOM will be prepended.
2167
2168`XLSX.utils.sheet_to_txt` takes the same arguments as `sheet_to_csv`.
2169
2170### HTML Output
2171
2172As an alternative to the `writeFile` HTML type, `XLSX.utils.sheet_to_html` also
2173produces HTML output. The function takes an options argument:
2174
2175| Option Name | Default | Description |
2176| :---------- | :------: | :-------------------------------------------------- |
2177|`id` | | Specify the `id` attribute for the `TABLE` element |
2178|`editable` | false | If true, set `contenteditable="true"` for every TD |
2179|`header` | | Override header (default `html body`) |
2180|`footer` | | Override footer (default `/body /html`) |
2181
2182<details>
2183 <summary><b>Examples</b> (click to show)</summary>
2184
2185For the example sheet:
2186
2187```js
2188> console.log(XLSX.utils.sheet_to_html(ws));
2189// ...
2190```
2191</details>
2192
2193### JSON
2194
2195`XLSX.utils.sheet_to_json` generates different types of JS objects. The function
2196takes an options argument:
2197
2198| Option Name | Default | Description |
2199| :---------- | :------: | :-------------------------------------------------- |
2200|`raw` | `true` | Use raw values (true) or formatted strings (false) |
2201|`range` | from WS | Override Range (see table below) |
2202|`header` | | Control output format (see table below) |
2203|`dateNF` | FMT 14 | Use specified date format in string output |
2204|`defval` | | Use specified value in place of null or undefined |
2205|`blankrows` | ** | Include blank lines in the output ** |
2206
2207- `raw` only affects cells which have a format code (`.z`) field or a formatted
2208 text (`.w`) field.
2209- If `header` is specified, the first row is considered a data row; if `header`
2210 is not specified, the first row is the header row and not considered data.
2211- When `header` is not specified, the conversion will automatically disambiguate
2212 header entries by affixing `_` and a count starting at `1`. For example, if
2213 three columns have header `foo` the output fields are `foo`, `foo_1`, `foo_2`
2214- `null` values are returned when `raw` is true but are skipped when false.
2215- If `defval` is not specified, null and undefined values are skipped normally.
2216 If specified, all null and undefined points will be filled with `defval`
2217- When `header` is `1`, the default is to generate blank rows. `blankrows` must
2218 be set to `false` to skip blank rows.
2219- When `header` is not `1`, the default is to skip blank rows. `blankrows` must
2220 be true to generate blank rows
2221
2222`range` is expected to be one of:
2223
2224| `range` | Description |
2225| :--------------- | :-------------------------------------------------------- |
2226| (number) | Use worksheet range but set starting row to the value |
2227| (string) | Use specified range (A1-style bounded range string) |
2228| (default) | Use worksheet range (`ws['!ref']`) |
2229
2230`header` is expected to be one of:
2231
2232| `header` | Description |
2233| :--------------- | :-------------------------------------------------------- |
2234| `1` | Generate an array of arrays ("2D Array") |
2235| `"A"` | Row object keys are literal column labels |
2236| array of strings | Use specified strings as keys in row objects |
2237| (default) | Read and disambiguate first row as keys |
2238
2239If header is not `1`, the row object will contain the non-enumerable property
2240`__rowNum__` that represents the row of the sheet corresponding to the entry.
2241
2242<details>
2243 <summary><b>Examples</b> (click to show)</summary>
2244
2245For the example sheet:
2246
2247```js
2248> XLSX.utils.sheet_to_json(ws);
2249[ { S: 1, h: 2, e: 3, e_1: 4, t: 5, J: 6, S_1: 7 },
2250 { S: 2, h: 3, e: 4, e_1: 5, t: 6, J: 7, S_1: 8 } ]
2251
2252> XLSX.utils.sheet_to_json(ws, {header:"A"});
2253[ { A: 'S', B: 'h', C: 'e', D: 'e', E: 't', F: 'J', G: 'S' },
2254 { A: '1', B: '2', C: '3', D: '4', E: '5', F: '6', G: '7' },
2255 { A: '2', B: '3', C: '4', D: '5', E: '6', F: '7', G: '8' } ]
2256
2257> XLSX.utils.sheet_to_json(ws, {header:["A","E","I","O","U","6","9"]});
2258[ { '6': 'J', '9': 'S', A: 'S', E: 'h', I: 'e', O: 'e', U: 't' },
2259 { '6': '6', '9': '7', A: '1', E: '2', I: '3', O: '4', U: '5' },
2260 { '6': '7', '9': '8', A: '2', E: '3', I: '4', O: '5', U: '6' } ]
2261
2262> XLSX.utils.sheet_to_json(ws, {header:1});
2263[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
2264 [ '1', '2', '3', '4', '5', '6', '7' ],
2265 [ '2', '3', '4', '5', '6', '7', '8' ] ]
2266```
2267
2268Example showing the effect of `raw`:
2269
2270```js
2271> ws['A2'].w = "3"; // set A2 formatted string value
2272
2273> XLSX.utils.sheet_to_json(ws, {header:1, raw:false});
2274[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
2275 [ '3', '2', '3', '4', '5', '6', '7' ], // <-- A2 uses the formatted string
2276 [ '2', '3', '4', '5', '6', '7', '8' ] ]
2277
2278> XLSX.utils.sheet_to_json(ws, {header:1});
2279[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
2280 [ 1, 2, 3, 4, 5, 6, 7 ], // <-- A2 uses the raw value
2281 [ 2, 3, 4, 5, 6, 7, 8 ] ]
2282```
2283</details>
2284
2285## File Formats
2286
2287Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
2288
2289| Format | Read | Write |
2290|:-------------------------------------------------------------|:-----:|:-----:|
2291| **Excel Worksheet/Workbook Formats** |:-----:|:-----:|
2292| Excel 2007+ XML Formats (XLSX/XLSM) | :o: | :o: |
2293| Excel 2007+ Binary Format (XLSB BIFF12) | :o: | :o: |
2294| Excel 2003-2004 XML Format (XML "SpreadsheetML") | :o: | :o: |
2295| Excel 97-2004 (XLS BIFF8) | :o: | :o: |
2296| Excel 5.0/95 (XLS BIFF5) | :o: | :o: |
2297| Excel 4.0 (XLS/XLW BIFF4) | :o: | |
2298| Excel 3.0 (XLS BIFF3) | :o: | |
2299| Excel 2.0/2.1 (XLS BIFF2) | :o: | :o: |
2300| **Excel Supported Text Formats** |:-----:|:-----:|
2301| Delimiter-Separated Values (CSV/TXT) | :o: | :o: |
2302| Data Interchange Format (DIF) | :o: | :o: |
2303| Symbolic Link (SYLK/SLK) | :o: | :o: |
2304| Lotus Formatted Text (PRN) | :o: | :o: |
2305| UTF-16 Unicode Text (TXT) | :o: | :o: |
2306| **Other Workbook/Worksheet Formats** |:-----:|:-----:|
2307| OpenDocument Spreadsheet (ODS) | :o: | :o: |
2308| Flat XML ODF Spreadsheet (FODS) | :o: | :o: |
2309| Uniform Office Format Spreadsheet (标文通 UOS1/UOS2) | :o: | |
2310| dBASE II/III/IV / Visual FoxPro (DBF) | :o: | :o: |
2311| Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123) | :o: | |
2312| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | :o: | |
2313| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
2314| HTML Tables | :o: | :o: |
2315| Rich Text Format tables (RTF) | | :o: |
2316| Ethercalc Record Format (ETH) | :o: | :o: |
2317
2318Features not supported by a given file format will not be written. Formats with
2319range limits will be silently truncated:
2320
2321| Format | Last Cell | Max Cols | Max Rows |
2322|:------------------------------------------|:-----------|---------:|---------:|
2323| Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
2324| Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
2325| Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
2326| Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
2327| Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
2328
2329Excel 2003 SpreadsheetML range limits are governed by the version of Excel and
2330are not enforced by the writer.
2331
2332### Excel 2007+ XML (XLSX/XLSM)
2333
2334<details>
2335 <summary>(click to show)</summary>
2336
2337XLSX and XLSM files are ZIP containers containing a series of XML files in
2338accordance with the Open Packaging Conventions (OPC). The XLSM format, almost
2339identical to XLSX, is used for files containing macros.
2340
2341The format is standardized in ECMA-376 and later in ISO/IEC 29500. Excel does
2342not follow the specification, and there are additional documents discussing how
2343Excel deviates from the specification.
2344
2345</details>
2346
2347### Excel 2.0-95 (BIFF2/BIFF3/BIFF4/BIFF5)
2348
2349<details>
2350 <summary>(click to show)</summary>
2351
2352BIFF 2/3 XLS are single-sheet streams of binary records. Excel 4 introduced
2353the concept of a workbook (`XLW` files) but also had single-sheet `XLS` format.
2354The structure is largely similar to the Lotus 1-2-3 file formats. BIFF5/8/12
2355extended the format in various ways but largely stuck to the same record format.
2356
2357There is no official specification for any of these formats. Excel 95 can write
2358files in these formats, so record lengths and fields were determined by writing
2359in all of the supported formats and comparing files. Excel 2016 can generate
2360BIFF5 files, enabling a full suite of file tests starting from XLSX or BIFF2.
2361
2362</details>
2363
2364### Excel 97-2004 Binary (BIFF8)
2365
2366<details>
2367 <summary>(click to show)</summary>
2368
2369BIFF8 exclusively uses the Compound File Binary container format, splitting some
2370content into streams within the file. At its core, it still uses an extended
2371version of the binary record format from older versions of BIFF.
2372
2373The `MS-XLS` specification covers the basics of the file format, and other
2374specifications expand on serialization of features like properties.
2375
2376</details>
2377
2378### Excel 2003-2004 (SpreadsheetML)
2379
2380<details>
2381 <summary>(click to show)</summary>
2382
2383Predating XLSX, SpreadsheetML files are simple XML files. There is no official
2384and comprehensive specification, although MS has released documentation on the
2385format. Since Excel 2016 can generate SpreadsheetML files, mapping features is
2386pretty straightforward.
2387
2388</details>
2389
2390### Excel 2007+ Binary (XLSB, BIFF12)
2391
2392<details>
2393 <summary>(click to show)</summary>
2394
2395Introduced in parallel with XLSX, the XLSB format combines the BIFF architecture
2396with the content separation and ZIP container of XLSX. For the most part nodes
2397in an XLSX sub-file can be mapped to XLSB records in a corresponding sub-file.
2398
2399The `MS-XLSB` specification covers the basics of the file format, and other
2400specifications expand on serialization of features like properties.
2401
2402</details>
2403
2404### Delimiter-Separated Values (CSV/TXT)
2405
2406<details>
2407 <summary>(click to show)</summary>
2408
2409Excel CSV deviates from RFC4180 in a number of important ways. The generated
2410CSV files should generally work in Excel although they may not work in RFC4180
2411compatible readers. The parser should generally understand Excel CSV. The
2412writer proactively generates cells for formulae if values are unavailable.
2413
2414Excel TXT uses tab as the delimiter and code page 1200.
2415
2416Notes:
2417
2418- Like in Excel, files starting with `0x49 0x44 ("ID")` are treated as Symbolic
2419 Link files. Unlike Excel, if the file does not have a valid SYLK header, it
2420 will be proactively reinterpreted as CSV. There are some files with semicolon
2421 delimiter that align with a valid SYLK file. For the broadest compatibility,
2422 all cells with the value of `ID` are automatically wrapped in double-quotes.
2423
2424</details>
2425
2426### Other Workbook Formats
2427
2428<details>
2429 <summary>(click to show)</summary>
2430
2431Support for other formats is generally far XLS/XLSB/XLSX support, due in large
2432part to a lack of publicly available documentation. Test files were produced in
2433the respective apps and compared to their XLS exports to determine structure.
2434The main focus is data extraction.
2435
2436</details>
2437
2438#### Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123)
2439
2440<details>
2441 <summary>(click to show)</summary>
2442
2443The Lotus formats consist of binary records similar to the BIFF structure. Lotus
2444did release a specification decades ago covering the original WK1 format. Other
2445features were deduced by producing files and comparing to Excel support.
2446
2447</details>
2448
2449#### Quattro Pro (WQ1/WQ2/WB1/WB2/WB3/QPW)
2450
2451<details>
2452 <summary>(click to show)</summary>
2453
2454The Quattro Pro formats use binary records in the same way as BIFF and Lotus.
2455Some of the newer formats (namely WB3 and QPW) use a CFB enclosure just like
2456BIFF8 XLS.
2457
2458</details>
2459
2460#### OpenDocument Spreadsheet (ODS/FODS)
2461
2462<details>
2463 <summary>(click to show)</summary>
2464
2465ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to
2466SpreadsheetML. Both are detailed in the OASIS standard, but tools like LO/OO
2467add undocumented extensions. The parsers and writers do not implement the full
2468standard, instead focusing on parts necessary to extract and store raw data.
2469
2470</details>
2471
2472#### Uniform Office Spreadsheet (UOS1/2)
2473
2474<details>
2475 <summary>(click to show)</summary>
2476
2477UOS is a very similar format, and it comes in 2 varieties corresponding to ODS
2478and FODS respectively. For the most part, the difference between the formats
2479is in the names of tags and attributes.
2480
2481</details>
2482
2483### Other Single-Worksheet Formats
2484
2485Many older formats supported only one worksheet:
2486
2487#### dBASE and Visual FoxPro (DBF)
2488
2489<details>
2490 <summary>(click to show)</summary>
2491
2492DBF is really a typed table format: each column can only hold one data type and
2493each record omits type information. The parser generates a header row and
2494inserts records starting at the second row of the worksheet. The writer makes
2495files compatible with Visual FoxPro extensions.
2496
2497Multi-file extensions like external memos and tables are currently unsupported,
2498limited by the general ability to read arbitrary files in the web browser. The
2499reader understands DBF Level 7 extensions like DATETIME.
2500
2501</details>
2502
2503#### Symbolic Link (SYLK)
2504
2505<details>
2506 <summary>(click to show)</summary>
2507
2508There is no real documentation. All knowledge was gathered by saving files in
2509various versions of Excel to deduce the meaning of fields. Notes:
2510
2511- Plain formulae are stored in the RC form.
2512- Column widths are rounded to integral characters.
2513
2514</details>
2515
2516#### Lotus Formatted Text (PRN)
2517
2518<details>
2519 <summary>(click to show)</summary>
2520
2521There is no real documentation, and in fact Excel treats PRN as an output-only
2522file format. Nevertheless we can guess the column widths and reverse-engineer
2523the original layout. Excel's 240 character width limitation is not enforced.
2524
2525</details>
2526
2527#### Data Interchange Format (DIF)
2528
2529<details>
2530 <summary>(click to show)</summary>
2531
2532There is no unified definition. Visicalc DIF differs from Lotus DIF, and both
2533differ from Excel DIF. Where ambiguous, the parser/writer follows the expected
2534behavior from Excel. In particular, Excel extends DIF in incompatible ways:
2535
2536- Since Excel automatically converts numbers-as-strings to numbers, numeric
2537 string constants are converted to formulae: `"0.3" -> "=""0.3""`
2538- DIF technically expects numeric cells to hold the raw numeric data, but Excel
2539 permits formatted numbers (including dates)
2540- DIF technically has no support for formulae, but Excel will automatically
2541 convert plain formulae. Array formulae are not preserved.
2542
2543</details>
2544
2545#### HTML
2546
2547<details>
2548 <summary>(click to show)</summary>
2549
2550Excel HTML worksheets include special metadata encoded in styles. For example,
2551`mso-number-format` is a localized string containing the number format. Despite
2552the metadata the output is valid HTML, although it does accept bare `&` symbols.
2553
2554The writer adds type metadata to the TD elements via the `t` tag. The parser
2555looks for those tags and overrides the default interpretation. For example, text
2556like `<td>12345</td>` will be parsed as numbers but `<td t="s">12345</td>` will
2557be parsed as text.
2558
2559</details>
2560
2561#### Rich Text Format (RTF)
2562
2563<details>
2564 <summary>(click to show)</summary>
2565
2566Excel RTF worksheets are stored in clipboard when copying cells or ranges from a
2567worksheet. The supported codes are a subset of the Word RTF support.
2568
2569</details>
2570
2571#### Ethercalc Record Format (ETH)
2572
2573<details>
2574 <summary>(click to show)</summary>
2575
2576[Ethercalc](https://ethercalc.net/) is an open source web spreadsheet powered by
2577a record format reminiscent of SYLK wrapped in a MIME multi-part message.
2578
2579</details>
2580
2581
2582## Testing
2583
2584### Node
2585
2586<details>
2587 <summary>(click to show)</summary>
2588
2589`make test` will run the node-based tests. By default it runs tests on files in
2590every supported format. To test a specific file type, set `FMTS` to the format
2591you want to test. Feature-specific tests are available with `make test_misc`
2592
2593```bash
2594$ make test_misc # run core tests
2595$ make test # run full tests
2596$ make test_xls # only use the XLS test files
2597$ make test_xlsx # only use the XLSX test files
2598$ make test_xlsb # only use the XLSB test files
2599$ make test_xml # only use the XML test files
2600$ make test_ods # only use the ODS test files
2601```
2602
2603To enable all errors, set the environment variable `WTF=1`:
2604
2605```bash
2606$ make test # run full tests
2607$ WTF=1 make test # enable all error messages
2608```
2609
2610`flow` and `eslint` checks are available:
2611
2612```bash
2613$ make lint # eslint checks
2614$ make flow # make lint + Flow checking
2615$ make tslint # check TS definitions
2616```
2617
2618</details>
2619
2620### Browser
2621
2622<details>
2623 <summary>(click to show)</summary>
2624
2625The core in-browser tests are available at `tests/index.html` within this repo.
2626Start a local server and navigate to that directory to run the tests.
2627`make ctestserv` will start a server on port 8000.
2628
2629`make ctest` will generate the browser fixtures. To add more files, edit the
2630`tests/fixtures.lst` file and add the paths.
2631
2632To run the full in-browser tests, clone the repo for
2633[`oss.sheetjs.com`](https://github.com/SheetJS/SheetJS.github.io) and replace
2634the `xlsx.js` file (then open a browser window and go to `stress.html`):
2635
2636```bash
2637$ cp xlsx.js ../SheetJS.github.io
2638$ cd ../SheetJS.github.io
2639$ simplehttpserver # or "python -mSimpleHTTPServer" or "serve"
2640$ open -a Chromium.app http://localhost:8000/stress.html
2641```
2642</details>
2643
2644### Tested Environments
2645
2646<details>
2647 <summary>(click to show)</summary>
2648
2649 - NodeJS `0.8`, `0.10`, `0.12`, `4.x`, `5.x`, `6.x`, `7.x`, `8.x`
2650 - IE 6/7/8/9/10/11 (IE 6-9 require shims)
2651 - Chrome 24+ (including Android 4.0+)
2652 - Safari 6+ (iOS and Desktop)
2653 - Edge 13+, FF 18+, and Opera 12+
2654
2655Tests utilize the mocha testing framework. Travis-CI and Sauce Labs links:
2656
2657 - <https://travis-ci.org/SheetJS/js-xlsx> for XLSX module in nodejs
2658 - <https://semaphoreci.com/sheetjs/js-xlsx> for XLSX module in nodejs
2659 - <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS\* modules
2660 - <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs
2661
2662The Travis-CI test suite also includes tests for various time zones. To change
2663the timezone locally, set the TZ environment variable:
2664
2665```bash
2666$ env TZ="Asia/Kolkata" WTF=1 make test_misc
2667```
2668
2669</details>
2670
2671### Test Files
2672
2673Test files are housed in [another repo](https://github.com/SheetJS/test_files).
2674
2675Running `make init` will refresh the `test_files` submodule and get the files.
2676Note that this requires `svn`, `git`, `hg` and other commands that may not be
2677available. If `make init` fails, please download the latest version of the test
2678files snapshot from [the repo](https://github.com/SheetJS/test_files/releases)
2679
2680<details>
2681 <summary><b>Latest Snapshot</b> (click to show)</summary>
2682
2683Latest test files snapshot:
2684<http://github.com/SheetJS/test_files/releases/download/20170409/test_files.zip>
2685
2686(download and unzip to the `test_files` subdirectory)
2687
2688</details>
2689
2690## Contributing
2691
2692Due to the precarious nature of the Open Specifications Promise, it is very
2693important to ensure code is cleanroom. [Contribution Notes](CONTRIBUTING.md)
2694
2695<details>
2696 <summary><b>File organization</b> (click to show)</summary>
2697
2698At a high level, the final script is a concatenation of the individual files in
2699the `bits` folder. Running `make` should reproduce the final output on all
2700platforms. The README is similarly split into bits in the `docbits` folder.
2701
2702Folders:
2703
2704| folder | contents |
2705|:-------------|:--------------------------------------------------------------|
2706| `bits` | raw source files that make up the final script |
2707| `docbits` | raw markdown files that make up `README.md` |
2708| `bin` | server-side bin scripts (`xlsx.njs`) |
2709| `dist` | dist files for web browsers and nonstandard JS environments |
2710| `demos` | demo projects for platforms like ExtendScript and Webpack |
2711| `tests` | browser tests (run `make ctest` to rebuild) |
2712| `types` | typescript definitions and tests |
2713| `misc` | miscellaneous supporting scripts |
2714| `test_files` | test files (pulled from the test files repository) |
2715
2716</details>
2717
2718After cloning the repo, running `make help` will display a list of commands.
2719
2720### OSX/Linux
2721
2722<details>
2723 <summary>(click to show)</summary>
2724
2725The `xlsx.js` file is constructed from the files in the `bits` subdirectory. The
2726build script (run `make`) will concatenate the individual bits to produce the
2727script. Before submitting a contribution, ensure that running make will produce
2728the `xlsx.js` file exactly. The simplest way to test is to add the script:
2729
2730```bash
2731$ git add xlsx.js
2732$ make clean
2733$ make
2734$ git diff xlsx.js
2735```
2736
2737To produce the dist files, run `make dist`. The dist files are updated in each
2738version release and *should not be committed between versions*.
2739</details>
2740
2741### Windows
2742
2743<details>
2744 <summary>(click to show)</summary>
2745
2746The included `make.cmd` script will build `xlsx.js` from the `bits` directory.
2747Building is as simple as:
2748
2749```cmd
2750> make
2751```
2752
2753To prepare development environment:
2754
2755```cmd
2756> make init
2757```
2758
2759The full list of commands available in Windows are displayed in `make help`:
2760
2761```
2762make init -- install deps and global modules
2763make lint -- run eslint linter
2764make test -- run mocha test suite
2765make misc -- run smaller test suite
2766make book -- rebuild README and summary
2767make help -- display this message
2768```
2769
2770As explained in [Test Files](#test-files), on Windows the release ZIP file must
2771be downloaded and extracted. If Bash on Windows is available, it is possible
2772to run the OSX/Linux workflow. The following steps prepares the environment:
2773
2774```bash
2775# Install support programs for the build and test commands
2776sudo apt-get install make git subversion mercurial
2777
2778# Install nodejs and NPM within the WSL
2779wget -qO- https://deb.nodesource.com/setup_8.x | sudo bash
2780sudo apt-get install nodejs
2781
2782# Install dev dependencies
2783sudo npm install -g mocha voc blanket xlsjs
2784```
2785
2786</details>
2787
2788### Tests
2789
2790<details>
2791 <summary>(click to show)</summary>
2792
2793The `test_misc` target (`make test_misc` on Linux/OSX / `make misc` on Windows)
2794runs the targeted feature tests. It should take 5-10 seconds to perform feature
2795tests without testing against the entire test battery. New features should be
2796accompanied with tests for the relevant file formats and features.
2797
2798For tests involving the read side, an appropriate feature test would involve
2799reading an existing file and checking the resulting workbook object. If a
2800parameter is involved, files should be read with different values to verify that
2801the feature is working as expected.
2802
2803For tests involving a new write feature which can already be parsed, appropriate
2804feature tests would involve writing a workbook with the feature and then opening
2805and verifying that the feature is preserved.
2806
2807For tests involving a new write feature without an existing read ability, please
2808add a feature test to the kitchen sink `tests/write.js`.
2809</details>
2810
2811## License
2812
2813Please consult the attached LICENSE file for details. All rights not explicitly
2814granted by the Apache 2.0 License are reserved by the Original Author.
2815
2816
2817## References
2818
2819<details>
2820 <summary><b>OSP-covered Specifications</b> (click to show)</summary>
2821
2822 - `MS-CFB`: Compound File Binary File Format
2823 - `MS-CTXLS`: Excel Custom Toolbar Binary File Format
2824 - `MS-EXSPXML3`: Excel Calculation Version 2 Web Service XML Schema
2825 - `MS-ODATA`: Open Data Protocol (OData)
2826 - `MS-ODRAW`: Office Drawing Binary File Format
2827 - `MS-ODRAWXML`: Office Drawing Extensions to Office Open XML Structure
2828 - `MS-OE376`: Office Implementation Information for ECMA-376 Standards Support
2829 - `MS-OFFCRYPTO`: Office Document Cryptography Structure
2830 - `MS-OI29500`: Office Implementation Information for ISO/IEC 29500 Standards Support
2831 - `MS-OLEDS`: Object Linking and Embedding (OLE) Data Structures
2832 - `MS-OLEPS`: Object Linking and Embedding (OLE) Property Set Data Structures
2833 - `MS-OODF3`: Office Implementation Information for ODF 1.2 Standards Support
2834 - `MS-OSHARED`: Office Common Data Types and Objects Structures
2835 - `MS-OVBA`: Office VBA File Format Structure
2836 - `MS-XLDM`: Spreadsheet Data Model File Format
2837 - `MS-XLS`: Excel Binary File Format (.xls) Structure Specification
2838 - `MS-XLSB`: Excel (.xlsb) Binary File Format
2839 - `MS-XLSX`: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
2840 - `XLS`: Microsoft Office Excel 97-2007 Binary File Format Specification
2841 - `RTF`: Rich Text Format
2842
2843</details>
2844
2845- ISO/IEC 29500:2012(E) "Information technology — Document description and processing languages — Office Open XML File Formats"
2846- Open Document Format for Office Applications Version 1.2 (29 September 2011)
2847- Worksheet File Format (From Lotus) December 1984