1654717680
NullAway is a tool to help eliminate NullPointerException
s (NPEs) in your Java code. To use NullAway, first add @Nullable
annotations in your code wherever a field, method parameter, or return value may be null
. Given these annotations, NullAway performs a series of type-based, local checks to ensure that any pointer that gets dereferenced in your code cannot be null
. NullAway is similar to the type-based nullability checking in the Kotlin and Swift languages, and the Checker Framework and Eradicate null checkers for Java.
NullAway is fast. It is built as a plugin to Error Prone and can run on every single build of your code. In our measurements, the build-time overhead of running NullAway is usually less than 10%. NullAway is also practical: it does not prevent all possible NPEs in your code, but it catches most of the NPEs we have observed in production while imposing a reasonable annotation burden, giving a great "bang for your buck."
NullAway requires that you build your code with Error Prone, version 2.4.0 or higher. See the Error Prone documentation for instructions on getting started with Error Prone and integration with your build system. The instructions below assume you are using Gradle; see the docs for discussion of other build systems.
To integrate NullAway into your non-Android Java project, add the following to your build.gradle
file:
plugins {
// we assume you are already using the Java plugin
id "net.ltgt.errorprone" version "0.6"
}
dependencies {
annotationProcessor "com.uber.nullaway:nullaway:0.9.7"
// Optional, some source of nullability annotations.
// Not required on Android if you use the support
// library nullability annotations.
compileOnly "com.google.code.findbugs:jsr305:3.0.2"
errorprone "com.google.errorprone:error_prone_core:2.4.0"
errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks.withType(JavaCompile) {
// remove the if condition if you want to run NullAway on test code
if (!name.toLowerCase().contains("test")) {
options.errorprone {
check("NullAway", CheckSeverity.ERROR)
option("NullAway:AnnotatedPackages", "com.uber")
}
}
}
Let's walk through this script step by step. The plugins
section pulls in the Gradle Error Prone plugin for Error Prone integration. If you are using the older apply plugin
syntax instead of a plugins
block, the following is equivalent:
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.6"
}
}
apply plugin: 'net.ltgt.errorprone'
In dependencies
, the annotationProcessor
line loads NullAway, and the compileOnly
line loads a JSR 305 library which provides a suitable @Nullable
annotation (javax.annotation.Nullable
). NullAway allows for any @Nullable
annotation to be used, so, e.g., @Nullable
from the Android Support Library or JetBrains annotations is also fine. The errorprone
line ensures that a compatible version of Error Prone is used, and the errorproneJavac
line is needed for JDK 8 compatibility.
Finally, in the tasks.withType(JavaCompile)
section, we pass some configuration options to NullAway. First check("NullAway", CheckSeverity.ERROR)
sets NullAway issues to the error level (it's equivalent to the -Xep:NullAway:ERROR
standard Error Prone argument); by default NullAway emits warnings. Then, option("NullAway:AnnotatedPackages", "com.uber")
(equivalent to the -XepOpt:NullAway:AnnotatedPackages=com.uber
standard Error Prone argument), tells NullAway that source code in packages under the com.uber
namespace should be checked for null dereferences and proper usage of @Nullable
annotations, and that class files in these packages should be assumed to have correct usage of @Nullable
(see the docs for more detail). NullAway requires at least the AnnotatedPackages
configuration argument to run, in order to distinguish between annotated and unannotated code. See the configuration docs for other useful configuration options.
We recommend addressing all the issues that Error Prone reports, particularly those reported as errors (rather than warnings). But, if you'd like to try out NullAway without running other Error Prone checks, you can use options.errorprone.disableAllChecks
(equivalent to passing "-XepDisableAllChecks"
to the compiler, before the NullAway-specific arguments).
Snapshots of the development version are available in Sonatype's snapshots repository.
The configuration for an Android project is very similar to the Java case, with one key difference: The com.google.code.findbugs:jsr305:3.0.2
dependency can be removed; you can use the android.support.annotation.Nullable
annotation from the Android Support library.
dependencies {
annotationProcessor "com.uber.nullaway:nullaway:0.9.7"
errorprone "com.google.errorprone:error_prone_core:2.4.0"
errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
}
A complete Android build.gradle
example is here. Also see our sample app. (The sample app's build.gradle
is not suitable for direct copy-pasting, as some configuration is inherited from the top-level build.gradle
.)
Some annotation processors like Dagger and AutoValue generate code into the same package namespace as your own code. This can cause problems when setting NullAway to the ERROR
level as suggested above, since errors in this generated code will block the build. Currently the best solution to this problem is to completely disable Error Prone on generated code, using the -XepExcludedPaths
option added in Error Prone 2.13 (documented here, use options.errorprone.excludedPaths=
in Gradle). To use, figure out which directory contains the generated code, and add that directory to the excluded path regex.
Note for Dagger users: Dagger versions older than 2.12 can have bad interactions with NullAway; see here. Please update to Dagger 2.12 to fix the problem.
Unlike other annotation processors above, Lombok modifies the in-memory AST of the code it processes, which is the source of numerous incompatibilities with Error Prone and, consequently, NullAway.
We do not particularly recommend using NullAway with Lombok. However, NullAway encodes some knowledge of common Lombok annotations and we do try for best-effort compatibility. In particular, common usages like @lombok.Builder
and @Data
classes should be supported.
In order for NullAway to successfully detect Lombok generated code within the in-memory Java AST, the following configuration option must be passed to Lombok as part of an applicable lombok.config
file:
addLombokGeneratedAnnotation
This causes Lombok to add @lombok.Generated
to the methods/classes it generates. NullAway will ignore (i.e. not check) the implementation of this generated code, treating it as unannotated.
Let's see how NullAway works on a simple code example:
static void log(Object x) {
System.out.println(x.toString());
}
static void foo() {
log(null);
}
This code is buggy: when foo()
is called, the subsequent call to log()
will fail with an NPE. You can see this error in the NullAway sample app by running:
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
By default, NullAway assumes every method parameter, return value, and field is non-null, i.e., it can never be assigned a null
value. In the above code, the x
parameter of log()
is assumed to be non-null. So, NullAway reports the following error:
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
We can fix this error by allowing null
to be passed to log()
, with a @Nullable
annotation:
static void log(@Nullable Object x) {
System.out.println(x.toString());
}
With this annotation, NullAway points out the possible null dereference:
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
We can fix this warning by adding a null check:
static void log(@Nullable Object x) {
if (x != null) {
System.out.println(x.toString());
}
}
With this change, all the NullAway warnings are fixed.
For more details on NullAway's checks, error messages, and limitations, see our detailed guide.
Please feel free to open a GitHub issue if you have any questions on how to use NullAway. Or, you can join the NullAway Discord server and ask us a question there.
We'd love for you to contribute to NullAway! Please note that once you create a pull request, you will be asked to sign our Uber Contributor License Agreement.
Download Details:
Author: uber
Source Code: https://github.com/uber/NullAway
License: MIT license
1600135200
OpenJDk or Open Java Development Kit is a free, open-source framework of the Java Platform, Standard Edition (or Java SE). It contains the virtual machine, the Java Class Library, and the Java compiler. The difference between the Oracle OpenJDK and Oracle JDK is that OpenJDK is a source code reference point for the open-source model. Simultaneously, the Oracle JDK is a continuation or advanced model of the OpenJDK, which is not open source and requires a license to use.
In this article, we will be installing OpenJDK on Centos 8.
#tutorials #alternatives #centos #centos 8 #configuration #dnf #frameworks #java #java development kit #java ee #java environment variables #java framework #java jdk #java jre #java platform #java sdk #java se #jdk #jre #open java development kit #open source #openjdk #openjdk 11 #openjdk 8 #openjdk runtime environment
1684207573
Different types of files are used in Bash for different purposes. Many options are available in Bash to check if the particular file exists or not. The existence of the file can be checked using the file test operators with the “test” command or without the “test” command. The purposes of different types of file test operators to check the existence of the file are shown in this tutorial.
Many file test operators exist in Bash to check if a particular file exists or not. Some of them are mentioned in the following:
Operator | Purpose |
-f | It is used to check if the file exists and if it is a regular file. |
-d | It is used to check if the file exists as a directory. |
-e | It is used to check the existence of the file only. |
-h or -L | It is used to check if the file exists as a symbolic link. |
-r | It is used to check if the file exists as a readable file. |
-w | It is used to check if the file exists as a writable file. |
-x | It is used to check if the file exists as an executable file. |
-s | It is used to check if the file exists and if the file is nonzero. |
-b | It is used to check if the file exists as a block special file. |
-c | It is used to check if the file exists as a special character file. |
Many ways of checking the existence of the regular file are shown in this part of the tutorial.
Create a Bash file with the following script that takes the filename from the user and check whether the file exists in the current location or not using the -f operator in the “if” condition with the single third brackets ([]).
#!/bin/bash
#Take the filename
echo -n "Enter the filename: "
read filename
#Check whether the file exists or not using the -f operator
if [ -f "$filename" ]; then
echo "File exists."
else
echo "File does not exist."
fi
The script is executed twice in the following script. The non-existence filename is given in the first execution. The existing filename is given in the second execution. The “ls” command is executed to check whether the file exists or not.
Create a Bash file with the following script that takes the filename as a command-line argument and check whether the file exists in the current location or not using the -f operator in the “if” condition with the double third brackets ([[ ]]).
#!/bin/bash
#Take the filename from the command-line argument
filename=$1
#Check whether the argument is missing or not
if [ "$filename" != "" ]; then
#Check whether the file exists or not using the -f operator
if [[ -f "$filename" ]]; then
echo "File exists."
else
echo "File does not exist."
fi
else
echo "Argument is missing."
fi
The script is executed twice in the following script. No argument is given in the first execution. An existing filename is given as an argument in the second execution. The “ls” command is executed to check whether the file exists or not.
Create a Bash file with the following script that takes the filename as a command-line argument and check whether the file exists in the current location or not using the -f operator with the “test” command in the “if” condition.
#!/bin/bash
#Take the filename from the command-line argument
filename=$1
#Check whether the argument is missing or not
if [ $# -lt 1 ]; then
echo "No argument is given."
exit 1
fi
#Check whether the file exists or not using the -f operator
if test -f "$filename"; then
echo "File exists."
else
echo "File does not exist."
fi
The script is executed twice in the following script. No argument is given in the first execution. An existing filename is given in the second execution.
Create a Bash file with the following script that checks whether the file path exists or not using the -f operator with the “test” command in the “if” condition.
#!/bin/bash
#Set the filename with the directory location
filename='temp/courses.txt'
#Check whether the file exists or not using the -f operator
if test -f "$filename"; then
echo "File exists."
else
echo "File does not exist."
fi
The following output appears after executing the script:
The methods of checking whether a regular file exists or not in the current location or the particular location are shown in this tutorial using multiple examples.
Original article source at: https://linuxhint.com/
1684211760
Bash 中出于不同的目的使用不同类型的文件。Bash 中有许多选项可用于检查特定文件是否存在。可以使用带有“test”命令或不带有“test”命令的文件测试操作符来检查文件是否存在。本教程显示了不同类型的文件测试操作符检查文件是否存在的目的。
Bash 中存在许多文件测试运算符来检查特定文件是否存在。下面提到了其中一些:
操作员 | 目的 |
-F | 它用于检查文件是否存在以及它是否是常规文件。 |
-d | 它用于检查文件是否作为目录存在。 |
-e | 它仅用于检查文件是否存在。 |
-h 或 -L | 它用于检查文件是否作为符号链接存在。 |
-r | 它用于检查文件是否作为可读文件存在。 |
-w | 它用于检查文件是否作为可写文件存在。 |
-X | 它用于检查文件是否作为可执行文件存在。 |
-s | 它用于检查文件是否存在以及文件是否为非零。 |
-b | 它用于检查文件是否作为块特殊文件存在。 |
-C | 它用于检查文件是否作为特殊字符文件存在。 |
本教程的这一部分显示了许多检查常规文件是否存在的方法。
使用以下脚本创建一个 Bash 文件,该脚本从用户那里获取文件名,并在“if”条件中使用带有第三个括号 ([]) 的 -f 运算符检查文件是否存在于当前位置。
#!/bin/bash
#Take the filename
echo -n "Enter the filename: "
read filename
#Check whether the file exists or not using the -f operator
if [ -f "$filename" ]; then
echo "File exists."
else
echo "File does not exist."
fi
该脚本在以下脚本中执行了两次。不存在的文件名在第一次执行时给出。现有文件名在第二次执行时给出。执行“ls”命令来检查文件是否存在。
使用以下脚本创建一个 Bash 文件,该脚本将文件名作为命令行参数,并在“if”条件中使用 -f 运算符和双第三括号 ([[ ] ]).
#!/bin/bash
#Take the filename from the command-line argument
filename=$1
#Check whether the argument is missing or not
if [ "$filename" != "" ]; then
#Check whether the file exists or not using the -f operator
if [[ -f "$filename" ]]; then
echo "File exists."
else
echo "File does not exist."
fi
else
echo "Argument is missing."
fi
该脚本在以下脚本中执行了两次。第一次执行时不给出参数。在第二次执行中,将现有文件名作为参数给出。执行“ls”命令来检查文件是否存在。
使用以下将文件名作为命令行参数的脚本创建 Bash 文件,并在“if”条件下使用 -f 运算符和“test”命令检查文件是否存在于当前位置。
#!/bin/bash
#Take the filename from the command-line argument
filename=$1
#Check whether the argument is missing or not
if [ $# -lt 1 ]; then
echo "No argument is given."
exit 1
fi
#Check whether the file exists or not using the -f operator
if test -f "$filename"; then
echo "File exists."
else
echo "File does not exist."
fi
该脚本在以下脚本中执行了两次。第一次执行时不给出参数。第二次执行时给出一个现有的文件名。
使用以下脚本创建 Bash 文件,在“if”条件下使用 -f 运算符和“test”命令检查文件路径是否存在。
#!/bin/bash
#Set the filename with the directory location
filename='temp/courses.txt'
#Check whether the file exists or not using the -f operator
if test -f "$filename"; then
echo "File exists."
else
echo "File does not exist."
fi
执行脚本后出现如下输出:
本教程通过多个示例展示了检查当前位置或特定位置是否存在常规文件的方法。
文章原文出处:https: //linuxhint.com/
1684215440
Различные типы файлов используются в Bash для разных целей. В Bash доступно множество опций, позволяющих проверить, существует ли конкретный файл или нет. Существование файла можно проверить с помощью операторов проверки файлов с командой «test» или без команды «test». В этом руководстве показаны цели различных типов операторов проверки файлов для проверки существования файла.
В Bash существует множество операторов проверки файлов, чтобы проверить, существует ли конкретный файл или нет. Некоторые из них упоминаются в следующем:
Оператор | Цель |
-f | Он используется для проверки того, существует ли файл и является ли он обычным файлом. |
-д | Он используется для проверки существования файла в виде каталога. |
-е | Он используется только для проверки существования файла. |
-ч или -л | Он используется для проверки существования файла в виде символической ссылки. |
-р | Он используется для проверки того, существует ли файл как читаемый файл. |
-w | Он используется для проверки того, существует ли файл как файл, доступный для записи. |
-Икс | Он используется для проверки того, существует ли файл как исполняемый файл. |
-с | Он используется для проверки того, существует ли файл и не равен ли он нулю. |
-б | Он используется для проверки того, существует ли файл в виде специального блочного файла. |
-с | Он используется для проверки того, существует ли файл как файл со специальными символами. |
В этой части руководства показано множество способов проверки существования обычного файла.
Создайте файл Bash со следующим сценарием, который берет имя файла от пользователя и проверяет, существует ли файл в текущем местоположении или нет, используя оператор -f в условии «если» с одной третьей скобкой ([]).
#!/bin/bash
#Take the filename
echo -n "Enter the filename: "
read filename
#Check whether the file exists or not using the -f operator
if [ -f "$filename" ]; then
echo "File exists."
else
echo "File does not exist."
fi
Сценарий выполняется дважды в следующем сценарии. Несуществующее имя файла дается при первом выполнении. Существующее имя файла дается во втором исполнении. Команда «ls» выполняется, чтобы проверить, существует ли файл или нет.
Создайте файл Bash со следующим сценарием, который принимает имя файла в качестве аргумента командной строки и проверяет, существует ли файл в текущем местоположении или нет, используя оператор -f в условии «если» с двойными третьими скобками ([[] ]).
#!/bin/bash
#Take the filename from the command-line argument
filename=$1
#Check whether the argument is missing or not
if [ "$filename" != "" ]; then
#Check whether the file exists or not using the -f operator
if [[ -f "$filename" ]]; then
echo "File exists."
else
echo "File does not exist."
fi
else
echo "Argument is missing."
fi
Сценарий выполняется дважды в следующем сценарии. При первом выполнении аргумент не передается. Существующее имя файла задается в качестве аргумента при втором выполнении. Команда «ls» выполняется, чтобы проверить, существует ли файл или нет.
Создайте файл Bash со следующим сценарием, который принимает имя файла в качестве аргумента командной строки и проверяет, существует ли файл в текущем местоположении или нет, используя оператор -f с командой «test» в условии «if».
#!/bin/bash
#Take the filename from the command-line argument
filename=$1
#Check whether the argument is missing or not
if [ $# -lt 1 ]; then
echo "No argument is given."
exit 1
fi
#Check whether the file exists or not using the -f operator
if test -f "$filename"; then
echo "File exists."
else
echo "File does not exist."
fi
Сценарий выполняется дважды в следующем сценарии. При первом выполнении аргумент не передается. Существующее имя файла дается во втором исполнении.
Создайте файл Bash со следующим скриптом, который проверяет, существует ли путь к файлу или нет, используя оператор -f с командой «test» в условии «if».
#!/bin/bash
#Set the filename with the directory location
filename='temp/courses.txt'
#Check whether the file exists or not using the -f operator
if test -f "$filename"; then
echo "File exists."
else
echo "File does not exist."
fi
После выполнения скрипта появляется следующий вывод:
Методы проверки того, существует ли обычный файл в текущем местоположении или в конкретном месте, показаны в этом руководстве с использованием нескольких примеров.
Оригинальный источник статьи: https://linuxhint.com/
1644415980
The SheetJS Community Edition offers battle-tested open-source solutions for extracting useful data from almost any complex spreadsheet and generating new spreadsheets that will work with legacy and modern software alike.
SheetJS Pro offers solutions beyond data processing: Edit complex templates with ease; let out your inner Picasso with styling; make custom sheets with images/graphs/PivotTables; evaluate formula expressions and port calculations to web apps; automate common spreadsheet tasks, and much more!
Browser Test and Support Matrix
Supported File Formats
Diagram Legend (click to show)
Expand to show Table of Contents
The complete browser standalone build is saved to dist/xlsx.full.min.js
and can be directly added to a page with a script
tag:
<script lang="javascript" src="dist/xlsx.full.min.js"></script>
CDN Availability (click to show)
CDN | URL |
---|---|
unpkg | https://unpkg.com/xlsx/ |
jsDelivr | https://jsdelivr.com/package/npm/xlsx |
CDNjs | https://cdnjs.com/libraries/xlsx |
packd | https://bundle.run/xlsx@latest?name=XLSX |
For example, unpkg
makes the latest version available at:
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
Browser builds (click to show)
The complete single-file version is generated at dist/xlsx.full.min.js
A slimmer build is generated at dist/xlsx.mini.min.js
. Compared to full build:
Webpack and Browserify builds include optional modules by default. Webpack can be configured to remove support with resolve.alias
:
/* uncomment the lines below to remove support */
resolve: {
alias: { "./dist/cpexcel.js": "" } // <-- omit international support
}
With npm:
$ npm install xlsx
With bower:
$ bower install js-xlsx
dist/xlsx.extendscript.js
is an ExtendScript build for Photoshop and InDesign that is included in the npm
package. It can be directly referenced with a #include
directive:
#include "xlsx.extendscript.js"
Internet Explorer and ECMAScript 3 Compatibility (click to show)
For broad compatibility with JavaScript engines, the library is written using ECMAScript 3 language dialect as well as some ES5 features like Array#forEach
. Older browsers require shims to provide missing functions.
To use the shim, add the shim before the script tag that loads xlsx.js
:
<!-- add the shim first -->
<script type="text/javascript" src="shim.min.js"></script>
<!-- after the shim is referenced, add the library -->
<script type="text/javascript" src="xlsx.full.min.js"></script>
The script also includes IE_LoadFile
and IE_SaveFile
for loading and saving files in Internet Explorer versions 6-9. The xlsx.extendscript.js
script bundles the shim in a format suitable for Photoshop and other Adobe products.
Most scenarios involving spreadsheets and data can be broken into 5 parts:
Acquire Data: Data may be stored anywhere: local or remote files, databases, HTML TABLE, or even generated programmatically in the web browser.
Extract Data: For spreadsheet files, this involves parsing raw bytes to read the cell data. For general JS data, this involves reshaping the data.
Process Data: From generating summary statistics to cleaning data records, this step is the heart of the problem.
Package Data: This can involve making a new spreadsheet or serializing with JSON.stringify
or writing XML or simply flattening data for UI tools.
Release Data: Spreadsheet files can be uploaded to a server or written locally. Data can be presented to users in an HTML TABLE or data grid.
A common problem involves generating a valid spreadsheet export from data stored in an HTML table. In this example, an HTML TABLE on the page will be scraped, a row will be added to the bottom with the date of the report, and a new file will be generated and downloaded locally. XLSX.writeFile
takes care of packaging the data and attempting a local download:
// Acquire Data (reference to the HTML table)
var table_elt = document.getElementById("my-table-id");
// Extract Data (create a workbook object from the table)
var workbook = XLSX.utils.table_to_book(table_elt);
// Process Data (add a new row)
var ws = workbook.Sheets["Sheet1"];
XLSX.utils.sheet_add_aoa(ws, [["Created "+new Date().toISOString()]], {origin:-1});
// Package and Release Data (`writeFile` tries to write and save an XLSB file)
XLSX.writeFile(workbook, "Report.xlsb");
This library tries to simplify steps 2 and 4 with functions to extract useful data from spreadsheet files (read
/ readFile
) and generate new spreadsheet files from data (write
/ writeFile
). Additional utility functions like table_to_book
work with other common data sources like HTML tables.
This documentation and various demo projects cover a number of common scenarios and approaches for steps 1 and 5.
Utility functions help with step 3.
Data processing should fit in any workflow
The library does not impose a separate lifecycle. It fits nicely in websites and apps built using any framework. The plain JS data objects play nice with Web Workers and future APIs.
"Acquiring and Extracting Data" describes solutions for common data import scenarios.
"Writing Workbooks" describes solutions for common data export scenarios involving actual spreadsheet files.
"Utility Functions" details utility functions for translating JSON Arrays and other common JS structures into worksheet objects.
JavaScript is a powerful language for data processing
The "Common Spreadsheet Format" is a simple object representation of the core concepts of a workbook. The various functions in the library provide low-level tools for working with the object.
For friendly JS processing, there are utility functions for converting parts of a worksheet to/from an Array of Arrays. The following example combines powerful JS Array methods with a network request library to download data, select the information we want and create a workbook file:
Get Data from a JSON Endpoint and Generate a Workbook (click to show)
The goal is to generate a XLSB workbook of US President names and birthdays.
Acquire Data
Raw Data
https://theunitedstates.io/congress-legislators/executive.json has the desired data. For example, John Adams:
{
"id": { /* (data omitted) */ },
"name": {
"first": "John", // <-- first name
"last": "Adams" // <-- last name
},
"bio": {
"birthday": "1735-10-19", // <-- birthday
"gender": "M"
},
"terms": [
{ "type": "viceprez", /* (other fields omitted) */ },
{ "type": "viceprez", /* (other fields omitted) */ },
{ "type": "prez", /* (other fields omitted) */ } // <-- look for "prez"
]
}
Filtering for Presidents
The dataset includes Aaron Burr, a Vice President who was never President!
Array#filter
creates a new array with the desired rows. A President served at least one term with type
set to "prez"
. To test if a particular row has at least one "prez"
term, Array#some
is another native JS function. The complete filter would be:
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
Lining up the data
For this example, the name will be the first name combined with the last name (row.name.first + " " + row.name.last
) and the birthday will be the subfield row.bio.birthday
. Using Array#map
, the dataset can be massaged in one call:
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
The result is an array of "simple" objects with no nesting:
[
{ name: "George Washington", birthday: "1732-02-22" },
{ name: "John Adams", birthday: "1735-10-19" },
// ... one row per President
]
Extract Data
With the cleaned dataset, XLSX.utils.json_to_sheet
generates a worksheet:
const worksheet = XLSX.utils.json_to_sheet(rows);
XLSX.utils.book_new
creates a new workbook and XLSX.utils.book_append_sheet
appends a worksheet to the workbook. The new worksheet will be called "Dates":
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
Process Data
Fixing headers
By default, json_to_sheet
creates a worksheet with a header row. In this case, the headers come from the JS object keys: "name" and "birthday".
The headers are in cells A1 and B1. XLSX.utils.sheet_add_aoa
can write text values to the existing worksheet starting at cell A1:
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
Fixing Column Widths
Some of the names are longer than the default column width. Column widths are set by setting the "!cols"
worksheet property.
The following line sets the width of column A to approximately 10 characters:
worksheet["!cols"] = [ { wch: 10 } ]; // set column A width to 10 characters
One Array#reduce
call over rows
can calculate the maximum width:
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
Note: If the starting point was a file or HTML table, XLSX.utils.sheet_to_json
will generate an array of JS objects.
Package and Release Data
XLSX.writeFile
creates a spreadsheet file and tries to write it to the system. In the browser, it will try to prompt the user to download the file. In NodeJS, it will write to the local directory.
XLSX.writeFile(workbook, "Presidents.xlsx");
Complete Example
// Uncomment the next line for use in NodeJS:
// const XLSX = require("xlsx"), axios = require("axios");
(async() => {
/* fetch JSON data and parse */
const url = "https://theunitedstates.io/congress-legislators/executive.json";
const raw_data = (await axios(url, {responseType: "json"})).data;
/* filter for the Presidents */
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* flatten objects */
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsx */
XLSX.writeFile(workbook, "Presidents.xlsx");
})();
For use in the web browser, assuming the snippet is saved to snippet.js
, script tags should be used to include the axios
and xlsx
standalone builds:
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="snippet.js"></script>
File formats are implementation details
The parser covers a wide gamut of common spreadsheet file formats to ensure that "HTML-saved-as-XLS" files work as well as actual XLS or XLSX files.
The writer supports a number of common output formats for broad compatibility with the data ecosystem.
To the greatest extent possible, data processing code should not have to worry about the specific file formats involved.
The demos
directory includes sample projects for:
Frameworks and APIs
angularjs
angular and ionic
knockout
meteor
react and react-native
vue 2.x and weex
XMLHttpRequest and fetch
nodejs server
databases and key/value stores
typed arrays and math
Bundlers and Tooling
Platforms and Integrations
electron application
nw.js application
Chrome / Chromium extensions
Adobe ExtendScript
Headless Browsers
canvas-datagrid
x-spreadsheet
Swift JSC and other engines
"serverless" functions
internet explorer
Other examples are included in the showcase.
Extract data from spreadsheet bytes
var workbook = XLSX.read(data, opts);
The read
method can extract data from spreadsheet bytes stored in a JS string, "binary string", NodeJS buffer or typed array (Uint8Array
or ArrayBuffer
).
Read spreadsheet bytes from a local file and extract data
var workbook = XLSX.readFile(filename, opts);
The readFile
method attempts to read a spreadsheet file at the supplied path. Browsers generally do not allow reading files in this way (it is deemed a security risk), and attempts to read files in this way will throw an error.
The second opts
argument is optional. "Parsing Options" covers the supported properties and behaviors.
Here are a few common scenarios (click on each subtitle to see the code):
Local file in a NodeJS server (click to show)
readFile
uses fs.readFileSync
under the hood:
var XLSX = require("xlsx");
var workbook = XLSX.readFile("test.xlsx");
For Node ESM, the readFile
helper is not enabled. Instead, fs.readFileSync
should be used to read the file data as a Buffer
for use with XLSX.read
:
import { readFileSync } from "fs";
import { read } from "xlsx/xlsx.mjs";
const buf = readFileSync("test.xlsx");
/* buf is a Buffer */
const workbook = read(buf);
User-submitted file in a web page ("Drag-and-Drop") (click to show)
For modern websites targeting Chrome 76+, File#arrayBuffer
is recommended:
// XLSX is a global from the standalone script
async function handleDropAsync(e) {
e.stopPropagation(); e.preventDefault();
const f = e.dataTransfer.files[0];
/* f is a File */
const data = await f.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
}
drop_dom_element.addEventListener("drop", handleDropAsync, false);
For maximal compatibility, the FileReader
API should be used:
function handleDrop(e) {
e.stopPropagation(); e.preventDefault();
var f = e.dataTransfer.files[0];
/* f is a File */
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
/* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */
var workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsArrayBuffer(f);
}
drop_dom_element.addEventListener("drop", handleDrop, false);
https://oss.sheetjs.com/sheetjs/ demonstrates the FileReader technique.
User-submitted file with an HTML INPUT element (click to show)
Starting with an HTML INPUT element with type="file"
:
<input type="file" id="input_dom_element">
For modern websites targeting Chrome 76+, Blob#arrayBuffer
is recommended:
// XLSX is a global from the standalone script
async function handleFileAsync(e) {
const file = e.target.files[0];
const data = await file.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
}
input_dom_element.addEventListener("change", handleFileAsync, false);
For broader support (including IE10+), the FileReader
approach is recommended:
function handleFile(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
/* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */
var workbook = XLSX.read(e.target.result);
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsArrayBuffer(file);
}
input_dom_element.addEventListener("change", handleFile, false);
The oldie
demo shows an IE-compatible fallback scenario.
Fetching a file in the web browser ("Ajax") (click to show)
For modern websites targeting Chrome 42+, fetch
is recommended:
// XLSX is a global from the standalone script
(async() => {
const url = "http://oss.sheetjs.com/test_files/formula_stress_test.xlsx";
const data = await (await fetch(url)).arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
})();
For broader support, the XMLHttpRequest
approach is recommended:
var url = "http://oss.sheetjs.com/test_files/formula_stress_test.xlsx";
/* set up async GET request */
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
var workbook = XLSX.read(req.response);
/* DO SOMETHING WITH workbook HERE */
};
req.send();
The xhr
demo includes a longer discussion and more examples.
http://oss.sheetjs.com/sheetjs/ajax.html shows fallback approaches for IE6+.
Local file in a PhotoShop or InDesign plugin (click to show)
readFile
wraps the File
logic in Photoshop and other ExtendScript targets. The specified path should be an absolute path:
#include "xlsx.extendscript.js"
/* Read test.xlsx from the Documents folder */
var workbook = XLSX.readFile(Folder.myDocuments + "/test.xlsx");
The extendscript
demo includes a more complex example.
Local file in an Electron app (click to show)
readFile
can be used in the renderer process:
/* From the renderer process */
var XLSX = require("xlsx");
var workbook = XLSX.readFile(path);
Electron APIs have changed over time. The electron
demo shows a complete example and details the required version-specific settings.
Local file in a mobile app with React Native (click to show)
The react
demo includes a sample React Native app.
Since React Native does not provide a way to read files from the filesystem, a third-party library must be used. The following libraries have been tested:
The base64
encoding returns strings compatible with the base64
type:
import XLSX from "xlsx";
import { FileSystem } from "react-native-file-access";
const b64 = await FileSystem.readFile(path, "base64");
/* b64 is a base64 string */
const workbook = XLSX.read(b64, {type: "base64"});
The ascii
encoding returns binary strings compatible with the binary
type:
import XLSX from "xlsx";
import { readFile } from "react-native-fs";
const bstr = await readFile(path, "ascii");
/* bstr is a binary string */
const workbook = XLSX.read(bstr, {type: "binary"});
NodeJS Server File Uploads (click to show)
read
can accept a NodeJS buffer. readFile
can read files generated by a HTTP POST request body parser like formidable
:
const XLSX = require("xlsx");
const http = require("http");
const formidable = require("formidable");
const server = http.createServer((req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
/* grab the first file */
const f = Object.entries(files)[0][1];
const path = f.filepath;
const workbook = XLSX.readFile(path);
/* DO SOMETHING WITH workbook HERE */
});
}).listen(process.env.PORT || 7262);
The server
demo has more advanced examples.
Download files in a NodeJS process (click to show)
Node 17.5 and 18.0 have native support for fetch:
const XLSX = require("xlsx");
const data = await (await fetch(url)).arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
For broader compatibility, third-party modules are recommended.
request
requires a null
encoding to yield Buffers:
var XLSX = require("xlsx");
var request = require("request");
request({url: url, encoding: null}, function(err, resp, body) {
var workbook = XLSX.read(body);
/* DO SOMETHING WITH workbook HERE */
});
axios
works the same way in browser and in NodeJS:
const XLSX = require("xlsx");
const axios = require("axios");
(async() => {
const res = await axios.get(url, {responseType: "arraybuffer"});
/* res.data is a Buffer */
const workbook = XLSX.read(res.data);
/* DO SOMETHING WITH workbook HERE */
})();
Download files in an Electron app (click to show)
The net
module in the main process can make HTTP/HTTPS requests to external resources. Responses should be manually concatenated using Buffer.concat
:
const XLSX = require("xlsx");
const { net } = require("electron");
const req = net.request(url);
req.on("response", (res) => {
const bufs = []; // this array will collect all of the buffers
res.on("data", (chunk) => { bufs.push(chunk); });
res.on("end", () => {
const workbook = XLSX.read(Buffer.concat(bufs));
/* DO SOMETHING WITH workbook HERE */
});
});
req.end();
Readable Streams in NodeJS (click to show)
When dealing with Readable Streams, the easiest approach is to buffer the stream and process the whole thing at the end:
var fs = require("fs");
var XLSX = require("xlsx");
function process_RS(stream, cb) {
var buffers = [];
stream.on("data", function(data) { buffers.push(data); });
stream.on("end", function() {
var buffer = Buffer.concat(buffers);
var workbook = XLSX.read(buffer, {type:"buffer"});
/* DO SOMETHING WITH workbook IN THE CALLBACK */
cb(workbook);
});
}
ReadableStream in the browser (click to show)
When dealing with ReadableStream
, the easiest approach is to buffer the stream and process the whole thing at the end:
// XLSX is a global from the standalone script
async function process_RS(stream) {
/* collect data */
const buffers = [];
const reader = stream.getReader();
for(;;) {
const res = await reader.read();
if(res.value) buffers.push(res.value);
if(res.done) break;
}
/* concat */
const out = new Uint8Array(buffers.reduce((acc, v) => acc + v.length, 0));
let off = 0;
for(const u8 of arr) {
out.set(u8, off);
off += u8.length;
}
return out;
}
const data = await process_RS(stream);
/* data is Uint8Array */
const workbook = XLSX.read(data);
More detailed examples are covered in the included demos
JSON and JS data tend to represent single worksheets. This section will use a few utility functions to generate workbooks:
Create a new Worksheet
var workbook = XLSX.utils.book_new();
The book_new
utility function creates an empty workbook with no worksheets.
Append a Worksheet to a Workbook
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
The book_append_sheet
utility function appends a worksheet to the workbook. The third argument specifies the desired worksheet name. Multiple worksheets can be added to a workbook by calling the function multiple times.
Create a worksheet from an array of arrays of JS values
var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
The aoa_to_sheet
utility function walks an "array of arrays" in row-major order, generating a worksheet object. The following snippet generates a sheet with cell A1
set to the string A1
, cell B1
set to B2
, etc:
var worksheet = XLSX.utils.aoa_to_sheet([
["A1", "B1", "C1"],
["A2", "B2", "C2"],
["A3", "B3", "C3"]
])
"Array of Arrays Input" describes the function and the optional opts
argument in more detail.
Create a worksheet from an array of JS objects
var worksheet = XLSX.utils.json_to_sheet(jsa, opts);
The json_to_sheet
utility function walks an array of JS objects in order, generating a worksheet object. By default, it will generate a header row and one row per object in the array. The optional opts
argument has settings to control the column order and header output.
"Array of Objects Input" describes the function and the optional opts
argument in more detail.
"Zen of SheetJS" contains a detailed example "Get Data from a JSON Endpoint and Generate a Workbook"
The database
demo includes examples of working with databases and query results.
Create a worksheet by scraping an HTML TABLE in the page
var worksheet = XLSX.utils.table_to_sheet(dom_element, opts);
The table_to_sheet
utility function takes a DOM TABLE element and iterates through the rows to generate a worksheet. The opts
argument is optional. "HTML Table Input" describes the function in more detail.
Create a workbook by scraping an HTML TABLE in the page
var workbook = XLSX.utils.table_to_book(dom_element, opts);
The table_to_book
utility function follows the same logic as table_to_sheet
. After generating a worksheet, it creates a blank workbook and appends the spreadsheet.
The options argument supports the same options as table_to_sheet
, with the addition of a sheet
property to control the worksheet name. If the property is missing or no options are specified, the default name Sheet1
is used.
Here are a few common scenarios (click on each subtitle to see the code):
HTML TABLE element in a webpage (click to show)
<!-- include the standalone script and shim. this uses the UNPKG CDN -->
<script src="https://unpkg.com/xlsx/dist/shim.min.js"></script>
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<!-- example table with id attribute -->
<table id="tableau">
<tr><td>Sheet</td><td>JS</td></tr>
<tr><td>12345</td><td>67</td></tr>
</table>
<!-- this block should appear after the table HTML and the standalone script -->
<script type="text/javascript">
var workbook = XLSX.utils.table_to_book(document.getElementById("tableau"));
/* DO SOMETHING WITH workbook HERE */
</script>
Multiple tables on a web page can be converted to individual worksheets:
/* create new workbook */
var workbook = XLSX.utils.book_new();
/* convert table "table1" to worksheet named "Sheet1" */
var sheet1 = XLSX.utils.table_to_sheet(document.getElementById("table1"));
XLSX.utils.book_append_sheet(workbook, sheet1, "Sheet1");
/* convert table "table2" to worksheet named "Sheet2" */
var sheet2 = XLSX.utils.table_to_sheet(document.getElementById("table2"));
XLSX.utils.book_append_sheet(workbook, sheet2, "Sheet2");
/* workbook now has 2 worksheets */
Alternatively, the HTML code can be extracted and parsed:
var htmlstr = document.getElementById("tableau").outerHTML;
var workbook = XLSX.read(htmlstr, {type:"string"});
Chrome/Chromium Extension (click to show)
The chrome
demo shows a complete example and details the required permissions and other settings.
In an extension, it is recommended to generate the workbook in a content script and pass the object back to the extension:
/* in the worker script */
chrome.runtime.onMessage.addListener(function(msg, sender, cb) {
/* pass a message like { sheetjs: true } from the extension to scrape */
if(!msg || !msg.sheetjs) return;
/* create a new workbook */
var workbook = XLSX.utils.book_new();
/* loop through each table element */
var tables = document.getElementsByTagName("table")
for(var i = 0; i < tables.length; ++i) {
var worksheet = XLSX.utils.table_to_sheet(tables[i]);
XLSX.utils.book_append_sheet(workbook, worksheet, "Table" + i);
}
/* pass back to the extension */
return cb(workbook);
});
The full object format is described later in this README.
Reading a specific cell (click to show)
This example extracts the value stored in cell A1 from the first worksheet:
var first_sheet_name = workbook.SheetNames[0];
var address_of_cell = 'A1';
/* Get worksheet */
var worksheet = workbook.Sheets[first_sheet_name];
/* Find desired cell */
var desired_cell = worksheet[address_of_cell];
/* Get the value */
var desired_value = (desired_cell ? desired_cell.v : undefined);
Adding a new worksheet to a workbook (click to show)
This example uses XLSX.utils.aoa_to_sheet
to make a sheet and XLSX.utils.book_append_sheet
to append the sheet to the workbook:
var ws_name = "SheetJS";
/* make worksheet */
var ws_data = [
[ "S", "h", "e", "e", "t", "J", "S" ],
[ 1 , 2 , 3 , 4 , 5 ]
];
var ws = XLSX.utils.aoa_to_sheet(ws_data);
/* Add the worksheet to the workbook */
XLSX.utils.book_append_sheet(wb, ws, ws_name);
Creating a new workbook from scratch (click to show)
The workbook object contains a SheetNames
array of names and a Sheets
object mapping sheet names to sheet objects. The XLSX.utils.book_new
utility function creates a new workbook object:
/* create a new blank workbook */
var wb = XLSX.utils.book_new();
The new workbook is blank and contains no worksheets. The write functions will error if the workbook is empty.
https://sheetjs.com/demos/modify.html read + modify + write files
https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs node
The node version installs a command line tool xlsx
which can read spreadsheet files and output the contents in various formats. The source is available at xlsx.njs
in the bin directory.
Some helper functions in XLSX.utils
generate different views of the sheets:
XLSX.utils.sheet_to_csv
generates CSVXLSX.utils.sheet_to_txt
generates UTF16 Formatted TextXLSX.utils.sheet_to_html
generates HTMLXLSX.utils.sheet_to_json
generates an array of objectsXLSX.utils.sheet_to_formulae
generates a list of formulaeFor writing, the first step is to generate output data. The helper functions write
and writeFile
will produce the data in various formats suitable for dissemination. The second step is to actual share the data with the end point. Assuming workbook
is a workbook object:
nodejs write a file (click to show)
XLSX.writeFile
uses fs.writeFileSync
in server environments:
if(typeof require !== 'undefined') XLSX = require('xlsx');
/* output format determined by filename */
XLSX.writeFile(workbook, 'out.xlsb');
/* at this point, out.xlsb is a file that you can distribute */
Photoshop ExtendScript write a file (click to show)
writeFile
wraps the File
logic in Photoshop and other ExtendScript targets. The specified path should be an absolute path:
#include "xlsx.extendscript.js"
/* output format determined by filename */
XLSX.writeFile(workbook, 'out.xlsx');
/* at this point, out.xlsx is a file that you can distribute */
The extendscript
demo includes a more complex example.
Browser add TABLE element to page (click to show)
The sheet_to_html
utility function generates HTML code that can be added to any DOM element.
var worksheet = workbook.Sheets[workbook.SheetNames[0]];
var container = document.getElementById('tableau');
container.innerHTML = XLSX.utils.sheet_to_html(worksheet);
Browser upload file (ajax) (click to show)
A complete example using XHR is included in the XHR demo, along with examples for fetch and wrapper libraries. This example assumes the server can handle Base64-encoded files (see the demo for a basic nodejs server):
/* in this example, send a base64 string to the server */
var wopts = { bookType:'xlsx', bookSST:false, type:'base64' };
var wbout = XLSX.write(workbook,wopts);
var req = new XMLHttpRequest();
req.open("POST", "/upload", true);
var formdata = new FormData();
formdata.append('file', 'test.xlsx'); // <-- server expects `file` to hold name
formdata.append('data', wbout); // <-- `data` holds the base64-encoded data
req.send(formdata);
Browser save file (click to show)
XLSX.writeFile
wraps a few techniques for triggering a file save:
URL
browser API creates an object URL for the file, which the library uses by creating a link and forcing a click. It is supported in modern browsers.msSaveBlob
is an IE10+ API for triggering a file save.IE_FileSave
uses VBScript and ActiveX to write a file in IE6+ for Windows XP and Windows 7. The shim must be included in the containing HTML page.There is no standard way to determine if the actual file has been downloaded.
/* output format determined by filename */
XLSX.writeFile(workbook, 'out.xlsb');
/* at this point, out.xlsb will have been downloaded */
Browser save file (compatibility) (click to show)
XLSX.writeFile
techniques work for most modern browsers as well as older IE. For much older browsers, there are workarounds implemented by wrapper libraries.
FileSaver.js
implements saveAs
. Note: XLSX.writeFile
will automatically call saveAs
if available.
/* bookType can be any supported output type */
var wopts = { bookType:'xlsx', bookSST:false, type:'array' };
var wbout = XLSX.write(workbook,wopts);
/* the saveAs call downloads a file on the local machine */
saveAs(new Blob([wbout],{type:"application/octet-stream"}), "test.xlsx");
Downloadify
uses a Flash SWF button to generate local files, suitable for environments where ActiveX is unavailable:
Downloadify.create(id,{
/* other options are required! read the downloadify docs for more info */
filename: "test.xlsx",
data: function() { return XLSX.write(wb, {bookType:"xlsx", type:'base64'}); },
append: false,
dataType: 'base64'
});
The oldie
demo shows an IE-compatible fallback scenario.
The included demos cover mobile apps and other special deployments.
The streaming write functions are available in the XLSX.stream
object. They take the same arguments as the normal write functions but return a Readable Stream. They are only exposed in NodeJS.
XLSX.stream.to_csv
is the streaming version of XLSX.utils.sheet_to_csv
.XLSX.stream.to_html
is the streaming version of XLSX.utils.sheet_to_html
.XLSX.stream.to_json
is the streaming version of XLSX.utils.sheet_to_json
.nodejs convert to CSV and write file (click to show)
var output_file_name = "out.csv";
var stream = XLSX.stream.to_csv(worksheet);
stream.pipe(fs.createWriteStream(output_file_name));
nodejs write JSON stream to screen (click to show)
/* to_json returns an object-mode stream */
var stream = XLSX.stream.to_json(worksheet, {raw:true});
/* the following stream converts JS objects to text via JSON.stringify */
var conv = new Transform({writableObjectMode:true});
conv._transform = function(obj, e, cb){ cb(null, JSON.stringify(obj) + "\n"); };
stream.pipe(conv); conv.pipe(process.stdout);
https://github.com/sheetjs/sheetaki pipes write streams to nodejs response.
XLSX
is the exposed variable in the browser and the exported node variable
XLSX.version
is the version of the library (added by the build script).
XLSX.SSF
is an embedded version of the format library.
XLSX.read(data, read_opts)
attempts to parse data
.
XLSX.readFile(filename, read_opts)
attempts to read filename
and parse.
Parse options are described in the Parsing Options section.
XLSX.write(wb, write_opts)
attempts to write the workbook wb
XLSX.writeFile(wb, filename, write_opts)
attempts to write wb
to filename
. In browser-based environments, it will attempt to force a client-side download.
XLSX.writeFileAsync(wb, filename, o, cb)
attempts to write wb
to filename
. If o
is omitted, the writer will use the third argument as the callback.
XLSX.stream
contains a set of streaming write functions.
Write options are described in the Writing Options section.
Utilities are available in the XLSX.utils
object and are described in the Utility Functions section:
Constructing:
book_new
creates an empty workbookbook_append_sheet
adds a worksheet to a workbookImporting:
aoa_to_sheet
converts an array of arrays of JS data to a worksheet.json_to_sheet
converts an array of JS objects to a worksheet.table_to_sheet
converts a DOM TABLE element to a worksheet.sheet_add_aoa
adds an array of arrays of JS data to an existing worksheet.sheet_add_json
adds an array of JS objects to an existing worksheet.Exporting:
sheet_to_json
converts a worksheet object to an array of JSON objects.sheet_to_csv
generates delimiter-separated-values output.sheet_to_txt
generates UTF16 formatted text.sheet_to_html
generates HTML output.sheet_to_formulae
generates a list of the formulae (with value fallbacks).Cell and cell address manipulation:
format_cell
generates the text value for a cell (using number formats).encode_row / decode_row
converts between 0-indexed rows and 1-indexed rows.encode_col / decode_col
converts between 0-indexed columns and column names.encode_cell / decode_cell
converts cell addresses.encode_range / decode_range
converts cell ranges.SheetJS conforms to the Common Spreadsheet Format (CSF):
Cell address objects are stored as {c:C, r:R}
where C
and R
are 0-indexed column and row numbers, respectively. For example, the cell address B5
is represented by the object {c:1, r:4}
.
Cell range objects are stored as {s:S, e:E}
where S
is the first cell and E
is the last cell in the range. The ranges are inclusive. For example, the range A3:B7
is represented by the object {s:{c:0, r:2}, e:{c:1, r:6}}
. Utility functions perform a row-major order walk traversal of a sheet range:
for(var R = range.s.r; R <= range.e.r; ++R) {
for(var C = range.s.c; C <= range.e.c; ++C) {
var cell_address = {c:C, r:R};
/* if an A1-style address is needed, encode the address */
var cell_ref = XLSX.utils.encode_cell(cell_address);
}
}
Cell objects are plain JS objects with keys and values following the convention:
Key | Description |
---|---|
v | raw value (see Data Types section for more info) |
w | formatted text (if applicable) |
t | type: b Boolean, e Error, n Number, d Date, s Text, z Stub |
f | cell formula encoded as an A1-style string (if applicable) |
F | range of enclosing array if formula is array formula (if applicable) |
r | rich text encoding (if applicable) |
h | HTML rendering of the rich text (if applicable) |
c | comments associated with the cell |
z | number format string associated with the cell (if requested) |
l | cell hyperlink object (.Target holds link, .Tooltip is tooltip) |
s | the style/theme of the cell (if applicable) |
Built-in export utilities (such as the CSV exporter) will use the w
text if it is available. To change a value, be sure to delete cell.w
(or set it to undefined
) before attempting to export. The utilities will regenerate the w
text from the number format (cell.z
) and the raw value if possible.
The actual array formula is stored in the f
field of the first cell in the array range. Other cells in the range will omit the f
field.
The raw value is stored in the v
value property, interpreted based on the t
type property. This separation allows for representation of numbers as well as numeric text. There are 6 valid cell types:
Type | Description |
---|---|
b | Boolean: value interpreted as JS boolean |
e | Error: value is a numeric code and w property stores common name ** |
n | Number: value is a JS number ** |
d | Date: value is a JS Date object or string to be parsed as Date ** |
s | Text: value interpreted as JS string and written as text ** |
z | Stub: blank stub cell that is ignored by data processing utilities ** |
Error values and interpretation (click to show)
Value | Error Meaning |
---|---|
0x00 | #NULL! |
0x07 | #DIV/0! |
0x0F | #VALUE! |
0x17 | #REF! |
0x1D | #NAME? |
0x24 | #NUM! |
0x2A | #N/A |
0x2B | #GETTING_DATA |
Type n
is the Number type. This includes all forms of data that Excel stores as numbers, such as dates/times and Boolean fields. Excel exclusively uses data that can be fit in an IEEE754 floating point number, just like JS Number, so the v
field holds the raw number. The w
field holds formatted text. Dates are stored as numbers by default and converted with XLSX.SSF.parse_date_code
.
Type d
is the Date type, generated only when the option cellDates
is passed. Since JSON does not have a natural Date type, parsers are generally expected to store ISO 8601 Date strings like you would get from date.toISOString()
. On the other hand, writers and exporters should be able to handle date strings and JS Date objects. Note that Excel disregards timezone modifiers and treats all dates in the local timezone. The library does not correct for this error.
Type s
is the String type. Values are explicitly stored as text. Excel will interpret these cells as "number stored as text". Generated Excel files automatically suppress that class of error, but other formats may elicit errors.
Type z
represents blank stub cells. They are generated in cases where cells have no assigned value but hold comments or other metadata. They are ignored by the core library data processing utility functions. By default these cells are not generated; the parser sheetStubs
option must be set to true
.
Excel Date Code details (click to show)
By default, Excel stores dates as numbers with a format code that specifies date processing. For example, the date 19-Feb-17
is stored as the number 42785
with a number format of d-mmm-yy
. The SSF
module understands number formats and performs the appropriate conversion.
XLSX also supports a special date type d
where the data is an ISO 8601 date string. The formatter converts the date back to a number.
The default behavior for all parsers is to generate number cells. Setting cellDates
to true will force the generators to store dates.
Time Zones and Dates (click to show)
Excel has no native concept of universal time. All times are specified in the local time zone. Excel limitations prevent specifying true absolute dates.
Following Excel, this library treats all dates as relative to local time zone.
Epochs: 1900 and 1904 (click to show)
Excel supports two epochs (January 1 1900 and January 1 1904). The workbook's epoch can be determined by examining the workbook's wb.Workbook.WBProps.date1904
property:
!!(((wb.Workbook||{}).WBProps||{}).date1904)
Each key that does not start with !
maps to a cell (using A-1
notation)
sheet[address]
returns the cell object for the specified address.
Special sheet keys (accessible as sheet[key]
, each starting with !
):
sheet['!ref']
: A-1 based range representing the sheet range. Functions that work with sheets should use this parameter to determine the range. Cells that are assigned outside of the range are not processed. In particular, when writing a sheet by hand, cells outside of the range are not included
Functions that handle sheets should test for the presence of !ref
field. If the !ref
is omitted or is not a valid range, functions are free to treat the sheet as empty or attempt to guess the range. The standard utilities that ship with this library treat sheets as empty (for example, the CSV output is empty string).
When reading a worksheet with the sheetRows
property set, the ref parameter will use the restricted range. The original range is set at ws['!fullref']
sheet['!margins']
: Object representing the page margins. The default values follow Excel's "normal" preset. Excel also has a "wide" and a "narrow" preset but they are stored as raw measurements. The main properties are listed below:
Page margin details (click to show)
key | description | "normal" | "wide" | "narrow" |
---|---|---|---|---|
left | left margin (inches) | 0.7 | 1.0 | 0.25 |
right | right margin (inches) | 0.7 | 1.0 | 0.25 |
top | top margin (inches) | 0.75 | 1.0 | 0.75 |
bottom | bottom margin (inches) | 0.75 | 1.0 | 0.75 |
header | header margin (inches) | 0.3 | 0.5 | 0.3 |
footer | footer margin (inches) | 0.3 | 0.5 | 0.3 |
/* Set worksheet sheet to "normal" */
ws["!margins"]={left:0.7, right:0.7, top:0.75,bottom:0.75,header:0.3,footer:0.3}
/* Set worksheet sheet to "wide" */
ws["!margins"]={left:1.0, right:1.0, top:1.0, bottom:1.0, header:0.5,footer:0.5}
/* Set worksheet sheet to "narrow" */
ws["!margins"]={left:0.25,right:0.25,top:0.75,bottom:0.75,header:0.3,footer:0.3}
In addition to the base sheet keys, worksheets also add:
ws['!cols']
: array of column properties objects. Column widths are actually stored in files in a normalized manner, measured in terms of the "Maximum Digit Width" (the largest width of the rendered digits 0-9, in pixels). When parsed, the column objects store the pixel width in the wpx
field, character width in the wch
field, and the maximum digit width in the MDW
field.
ws['!rows']
: array of row properties objects as explained later in the docs. Each row object encodes properties including row height and visibility.
ws['!merges']
: array of range objects corresponding to the merged cells in the worksheet. Plain text formats do not support merge cells. CSV export will write all cells in the merge range if they exist, so be sure that only the first cell (upper-left) in the range is set.
ws['!outline']
: configure how outlines should behave. Options default to the default settings in Excel 2019:
key | Excel feature | default |
---|---|---|
above | Uncheck "Summary rows below detail" | false |
left | Uncheck "Summary rows to the right of detail" | false |
ws['!protect']
: object of write sheet protection properties. The password
key specifies the password for formats that support password-protected sheets (XLSX/XLSB/XLS). The writer uses the XOR obfuscation method. The following keys control the sheet protection -- set to false
to enable a feature when sheet is locked or set to true
to disable a feature:Worksheet Protection Details (click to show)
key | feature (true=disabled / false=enabled) | default |
---|---|---|
selectLockedCells | Select locked cells | enabled |
selectUnlockedCells | Select unlocked cells | enabled |
formatCells | Format cells | disabled |
formatColumns | Format columns | disabled |
formatRows | Format rows | disabled |
insertColumns | Insert columns | disabled |
insertRows | Insert rows | disabled |
insertHyperlinks | Insert hyperlinks | disabled |
deleteColumns | Delete columns | disabled |
deleteRows | Delete rows | disabled |
sort | Sort | disabled |
autoFilter | Filter | disabled |
pivotTables | Use PivotTable reports | disabled |
objects | Edit objects | enabled |
scenarios | Edit scenarios | enabled |
ws['!autofilter']
: AutoFilter object following the schema:type AutoFilter = {
ref:string; // A-1 based range representing the AutoFilter table range
}
Chartsheets are represented as standard sheets. They are distinguished with the !type
property set to "chart"
.
The underlying data and !ref
refer to the cached data in the chartsheet. The first row of the chartsheet is the underlying header.
Macrosheets are represented as standard sheets. They are distinguished with the !type
property set to "macro"
.
Dialogsheets are represented as standard sheets. They are distinguished with the !type
property set to "dialog"
.
workbook.SheetNames
is an ordered list of the sheets in the workbook
wb.Sheets[sheetname]
returns an object representing the worksheet.
wb.Props
is an object storing the standard properties. wb.Custprops
stores custom properties. Since the XLS standard properties deviate from the XLSX standard, XLS parsing stores core properties in both places.
wb.Workbook
stores workbook-level attributes.
The various file formats use different internal names for file properties. The workbook Props
object normalizes the names:
File Properties (click to show)
JS Name | Excel Description |
---|---|
Title | Summary tab "Title" |
Subject | Summary tab "Subject" |
Author | Summary tab "Author" |
Manager | Summary tab "Manager" |
Company | Summary tab "Company" |
Category | Summary tab "Category" |
Keywords | Summary tab "Keywords" |
Comments | Summary tab "Comments" |
LastAuthor | Statistics tab "Last saved by" |
CreatedDate | Statistics tab "Created" |
For example, to set the workbook title property:
if(!wb.Props) wb.Props = {};
wb.Props.Title = "Insert Title Here";
Custom properties are added in the workbook Custprops
object:
if(!wb.Custprops) wb.Custprops = {};
wb.Custprops["Custom Property"] = "Custom Value";
Writers will process the Props
key of the options object:
/* force the Author to be "SheetJS" */
XLSX.write(wb, {Props:{Author:"SheetJS"}});
wb.Workbook
stores workbook-level attributes.
wb.Workbook.Names
is an array of defined name objects which have the keys:
Defined Name Properties (click to show)
Key | Description |
---|---|
Sheet | Name scope. Sheet Index (0 = first sheet) or null (Workbook) |
Name | Case-sensitive name. Standard rules apply ** |
Ref | A1-style Reference ("Sheet1!$A$1:$D$20" ) |
Comment | Comment (only applicable for XLS/XLSX/XLSB) |
Excel allows two sheet-scoped defined names to share the same name. However, a sheet-scoped name cannot collide with a workbook-scope name. Workbook writers may not enforce this constraint.
wb.Workbook.Views
is an array of workbook view objects which have the keys:
Key | Description |
---|---|
RTL | If true, display right-to-left |
wb.Workbook.WBProps
holds other workbook properties:
Key | Description |
---|---|
CodeName | VBA Project Workbook Code Name |
date1904 | epoch: 0/false for 1900 system, 1/true for 1904 |
filterPrivacy | Warn or strip personally identifying info on save |
Even for basic features like date storage, the official Excel formats store the same content in different ways. The parsers are expected to convert from the underlying file format representation to the Common Spreadsheet Format. Writers are expected to convert from CSF back to the underlying file format.
The A1-style formula string is stored in the f
field. Even though different file formats store the formulae in different ways, the formats are translated. Even though some formats store formulae with a leading equal sign, CSF formulae do not start with =
.
Representation of A1=1, A2=2, A3=A1+A2 (click to show)
{
"!ref": "A1:A3",
A1: { t:'n', v:1 },
A2: { t:'n', v:2 },
A3: { t:'n', v:3, f:'A1+A2' }
}
Shared formulae are decompressed and each cell has the formula corresponding to its cell. Writers generally do not attempt to generate shared formulae.
Cells with formula entries but no value will be serialized in a way that Excel and other spreadsheet tools will recognize. This library will not automatically compute formula results! For example, to compute BESSELJ
in a worksheet:
Formula without known value (click to show)
{
"!ref": "A1:A3",
A1: { t:'n', v:3.14159 },
A2: { t:'n', v:2 },
A3: { t:'n', f:'BESSELJ(A1,A2)' }
}
Array Formulae
Array formulae are stored in the top-left cell of the array block. All cells of an array formula have a F
field corresponding to the range. A single-cell formula can be distinguished from a plain formula by the presence of F
field.
Array Formula examples (click to show)
For example, setting the cell C1
to the array formula {=SUM(A1:A3*B1:B3)}
:
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
For a multi-cell array formula, every cell has the same array range but only the first cell specifies the formula. Consider D1:D3=A1:A3*B1:B3
:
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
worksheet['D2'] = { t:'n', F:"D1:D3" };
worksheet['D3'] = { t:'n', F:"D1:D3" };
Utilities and writers are expected to check for the presence of a F
field and ignore any possible formula element f
in cells other than the starting cell. They are not expected to perform validation of the formulae!
Formula Output Utility Function (click to show)
The sheet_to_formulae
method generates one line per formula or array formula. Array formulae are rendered in the form range=formula
while plain cells are rendered in the form cell=formula or value
. Note that string literals are prefixed with an apostrophe '
, consistent with Excel's formula bar display.
Formulae File Format Details (click to show)
Storage Representation | Formats | Read | Write |
---|---|---|---|
A1-style strings | XLSX | ✔ | ✔ |
RC-style strings | XLML and plain text | ✔ | ✔ |
BIFF Parsed formulae | XLSB and all XLS formats | ✔ | |
OpenFormula formulae | ODS/FODS/UOS | ✔ | ✔ |
Lotus Parsed formulae | All Lotus WK_ formats | ✔ |
Since Excel prohibits named cells from colliding with names of A1 or RC style cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula formulae can be converted with regular expressions.
Format Support (click to show)
Row Properties: XLSX/M, XLSB, BIFF8 XLS, XLML, SYLK, DOM, ODS
Column Properties: XLSX/M, XLSB, BIFF8 XLS, XLML, SYLK, DOM
Row and Column properties are not extracted by default when reading from a file and are not persisted by default when writing to a file. The option cellStyles: true
must be passed to the relevant read or write function.
Column Properties
The !cols
array in each worksheet, if present, is a collection of ColInfo
objects which have the following properties:
type ColInfo = {
/* visibility */
hidden?: boolean; // if true, the column is hidden
/* column width is specified in one of the following ways: */
wpx?: number; // width in screen pixels
width?: number; // width in Excel's "Max Digit Width", width*256 is integral
wch?: number; // width in characters
/* other fields for preserving features from files */
level?: number; // 0-indexed outline / group level
MDW?: number; // Excel's "Max Digit Width" unit, always integral
};
Row Properties
The !rows
array in each worksheet, if present, is a collection of RowInfo
objects which have the following properties:
type RowInfo = {
/* visibility */
hidden?: boolean; // if true, the row is hidden
/* row height is specified in one of the following ways: */
hpx?: number; // height in screen pixels
hpt?: number; // height in points
level?: number; // 0-indexed outline / group level
};
Outline / Group Levels Convention
The Excel UI displays the base outline level as 1
and the max level as 8
. Following JS conventions, SheetJS uses 0-indexed outline levels wherein the base outline level is 0
and the max level is 7
.
Why are there three width types? (click to show)
There are three different width types corresponding to the three different ways spreadsheets store column widths:
SYLK and other plain text formats use raw character count. Contemporaneous tools like Visicalc and Multiplan were character based. Since the characters had the same width, it sufficed to store a count. This tradition was continued into the BIFF formats.
SpreadsheetML (2003) tried to align with HTML by standardizing on screen pixel count throughout the file. Column widths, row heights, and other measures use pixels. When the pixel and character counts do not align, Excel rounds values.
XLSX internally stores column widths in a nebulous "Max Digit Width" form. The Max Digit Width is the width of the largest digit when rendered (generally the "0" character is the widest). The internal width must be an integer multiple of the the width divided by 256. ECMA-376 describes a formula for converting between pixels and the internal width. This represents a hybrid approach.
Read functions attempt to populate all three properties. Write functions will try to cycle specified values to the desired type. In order to avoid potential conflicts, manipulation should delete the other properties first. For example, when changing the pixel width, delete the wch
and width
properties.
Implementation details (click to show)
Row Heights
Excel internally stores row heights in points. The default resolution is 72 DPI or 96 PPI, so the pixel and point size should agree. For different resolutions they may not agree, so the library separates the concepts.
Even though all of the information is made available, writers are expected to follow the priority order:
hpx
pixel height if availablehpt
point height if availableColumn Widths
Given the constraints, it is possible to determine the MDW without actually inspecting the font! The parsers guess the pixel width by converting from width to pixels and back, repeating for all possible MDW and selecting the MDW that minimizes the error. XLML actually stores the pixel width, so the guess works in the opposite direction.
Even though all of the information is made available, writers are expected to follow the priority order:
width
field if availablewpx
pixel width if availablewch
character count if availableThe cell.w
formatted text for each cell is produced from cell.v
and cell.z
format. If the format is not specified, the Excel General
format is used. The format can either be specified as a string or as an index into the format table. Parsers are expected to populate workbook.SSF
with the number format table. Writers are expected to serialize the table.
Custom tools should ensure that the local table has each used format string somewhere in the table. Excel convention mandates that the custom formats start at index 164. The following example creates a custom format from scratch:
New worksheet with custom format (click to show)
var wb = {
SheetNames: ["Sheet1"],
Sheets: {
Sheet1: {
"!ref":"A1:C1",
A1: { t:"n", v:10000 }, // <-- General format
B1: { t:"n", v:10000, z: "0%" }, // <-- Builtin format
C1: { t:"n", v:10000, z: "\"T\"\ #0.00" } // <-- Custom format
}
}
}
The rules are slightly different from how Excel displays custom number formats. In particular, literal characters must be wrapped in double quotes or preceded by a backslash. For more info, see the Excel documentation article Create or delete a custom number format
or ECMA-376 18.8.31 (Number Formats)
Default Number Formats (click to show)
The default formats are listed in ECMA-376 18.8.30:
ID | Format |
---|---|
0 | General |
1 | 0 |
2 | 0.00 |
3 | #,##0 |
4 | #,##0.00 |
9 | 0% |
10 | 0.00% |
11 | 0.00E+00 |
12 | # ?/? |
13 | # ??/?? |
14 | m/d/yy (see below) |
15 | d-mmm-yy |
16 | d-mmm |
17 | mmm-yy |
18 | h:mm AM/PM |
19 | h:mm:ss AM/PM |
20 | h:mm |
21 | h:mm:ss |
22 | m/d/yy h:mm |
37 | #,##0 ;(#,##0) |
38 | #,##0 ;[Red](#,##0) |
39 | #,##0.00;(#,##0.00) |
40 | #,##0.00;[Red](#,##0.00) |
45 | mm:ss |
46 | [h]:mm:ss |
47 | mmss.0 |
48 | ##0.0E+0 |
49 | @ |
Format 14 (m/d/yy
) is localized by Excel: even though the file specifies that number format, it will be drawn differently based on system settings. It makes sense when the producer and consumer of files are in the same locale, but that is not always the case over the Internet. To get around this ambiguity, parse functions accept the dateNF
option to override the interpretation of that specific format string.
Format Support (click to show)
Cell Hyperlinks: XLSX/M, XLSB, BIFF8 XLS, XLML, ODS
Tooltips: XLSX/M, XLSB, BIFF8 XLS, XLML
Hyperlinks are stored in the l
key of cell objects. The Target
field of the hyperlink object is the target of the link, including the URI fragment. Tooltips are stored in the Tooltip
field and are displayed when you move your mouse over the text.
For example, the following snippet creates a link from cell A3
to https://sheetjs.com with the tip "Find us @ SheetJS.com!"
:
ws['A1'].l = { Target:"https://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
Note that Excel does not automatically style hyperlinks -- they will generally be displayed as normal text.
Remote Links
HTTP / HTTPS links can be used directly:
ws['A2'].l = { Target:"https://docs.sheetjs.com/#hyperlinks" };
ws['A3'].l = { Target:"http://localhost:7262/yes_localhost_works" };
Excel also supports mailto
email links with subject line:
ws['A4'].l = { Target:"mailto:ignored@dev.null" };
ws['A5'].l = { Target:"mailto:ignored@dev.null?subject=Test Subject" };
Local Links
Links to absolute paths should use the file://
URI scheme:
ws['B1'].l = { Target:"file:///SheetJS/t.xlsx" }; /* Link to /SheetJS/t.xlsx */
ws['B2'].l = { Target:"file:///c:/SheetJS.xlsx" }; /* Link to c:\SheetJS.xlsx */
Links to relative paths can be specified without a scheme:
ws['B3'].l = { Target:"SheetJS.xlsb" }; /* Link to SheetJS.xlsb */
ws['B4'].l = { Target:"../SheetJS.xlsm" }; /* Link to ../SheetJS.xlsm */
Relative Paths have undefined behavior in the SpreadsheetML 2003 format. Excel 2019 will treat a ..\
parent mark as two levels up.
Internal Links
Links where the target is a cell or range or defined name in the same workbook ("Internal Links") are marked with a leading hash character:
ws['C1'].l = { Target:"#E2" }; /* Link to cell E2 */
ws['C2'].l = { Target:"#Sheet2!E2" }; /* Link to cell E2 in sheet Sheet2 */
ws['C3'].l = { Target:"#SomeDefinedName" }; /* Link to Defined Name */
Cell comments are objects stored in the c
array of cell objects. The actual contents of the comment are split into blocks based on the comment author. The a
field of each comment object is the author of the comment and the t
field is the plain text representation.
For example, the following snippet appends a cell comment into cell A1
:
if(!ws.A1.c) ws.A1.c = [];
ws.A1.c.push({a:"SheetJS", t:"I'm a little comment, short and stout!"});
Note: XLSB enforces a 54 character limit on the Author name. Names longer than 54 characters may cause issues with other formats.
To mark a comment as normally hidden, set the hidden
property:
if(!ws.A1.c) ws.A1.c = [];
ws.A1.c.push({a:"SheetJS", t:"This comment is visible"});
if(!ws.A2.c) ws.A2.c = [];
ws.A2.c.hidden = true;
ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"});
Excel enables hiding sheets in the lower tab bar. The sheet data is stored in the file but the UI does not readily make it available. Standard hidden sheets are revealed in the "Unhide" menu. Excel also has "very hidden" sheets which cannot be revealed in the menu. It is only accessible in the VB Editor!
The visibility setting is stored in the Hidden
property of sheet props array.
More details (click to show)
Value | Definition |
---|---|
0 | Visible |
1 | Hidden |
2 | Very Hidden |
With https://rawgit.com/SheetJS/test_files/HEAD/sheet_visibility.xlsx:
> wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] })
[ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ]
Non-Excel formats do not support the Very Hidden state. The best way to test if a sheet is visible is to check if the Hidden
property is logical truth:
> wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] })
[ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ]
VBA Macros are stored in a special data blob that is exposed in the vbaraw
property of the workbook object when the bookVBA
option is true
. They are supported in XLSM
, XLSB
, and BIFF8 XLS
formats. The supported format writers automatically insert the data blobs if it is present in the workbook and associate with the worksheet names.
Custom Code Names (click to show)
The workbook code name is stored in wb.Workbook.WBProps.CodeName
. By default, Excel will write ThisWorkbook
or a translated phrase like DieseArbeitsmappe
. Worksheet and Chartsheet code names are in the worksheet properties object at wb.Workbook.Sheets[i].CodeName
. Macrosheets and Dialogsheets are ignored.
The readers and writers preserve the code names, but they have to be manually set when adding a VBA blob to a different workbook.
Macrosheets (click to show)
Older versions of Excel also supported a non-VBA "macrosheet" sheet type that stored automation commands. These are exposed in objects with the !type
property set to "macro"
.
Detecting macros in workbooks (click to show)
The vbaraw
field will only be set if macros are present, so testing is simple:
function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
if(!!wb.vbaraw) return true;
const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
return sheets.some((ws) => !!ws && ws['!type']=='macro');
}
The exported read
and readFile
functions accept an options argument:
Option Name | Default | Description |
---|---|---|
type | Input data encoding (see Input Type below) | |
raw | false | If true, plain text parsing will not parse values ** |
codepage | If specified, use code page when appropriate ** | |
cellFormula | true | Save formulae to the .f field |
cellHTML | true | Parse rich text and save HTML to the .h field |
cellNF | false | Save number format string to the .z field |
cellStyles | false | Save style/theme info to the .s field |
cellText | true | Generated formatted text to the .w field |
cellDates | false | Store dates as type d (default is n ) |
dateNF | If specified, use the string for date code 14 ** | |
sheetStubs | false | Create cell objects of type z for stub cells |
sheetRows | 0 | If >0, read the first sheetRows rows ** |
bookDeps | false | If true, parse calculation chains |
bookFiles | false | If true, add raw files to book object ** |
bookProps | false | If true, only parse enough to get book metadata ** |
bookSheets | false | If true, only parse enough to get the sheet names |
bookVBA | false | If true, copy VBA blob to vbaraw field ** |
password | "" | If defined and file is encrypted, use password ** |
WTF | false | If true, throw errors on unexpected file features ** |
sheets | If specified, only parse specified sheets ** | |
PRN | false | If true, allow parsing of PRN files ** |
xlfn | false | If true, preserve _xlfn. prefixes in formulae ** |
FS | DSV Field Separator override |
cellNF
is false, formatted text will be generated and saved to .w
bookSheets
is false.raw
option suppresses value parsing.bookSheets
and bookProps
combine to give both sets of informationDeps
will be an empty object if bookDeps
is falsebookFiles
behavior depends on file type:keys
array (paths in the ZIP) for ZIP-based formatsfiles
hash (mapping paths to objects representing the files) for ZIPcfb
object for formats using CFB containerssheetRows-1
rows will be generated when looking at the JSON object output (since the header row is counted as a row when parsing the data)sheets
restricts based on input type:0
is first worksheet)bookVBA
merely exposes the raw VBA CFB object. It does not parse the data. XLSM and XLSB store the VBA CFB object in xl/vbaProject.bin
. BIFF8 XLS mixes the VBA entries alongside the core Workbook entry, so the library generates a new XLSB-compatible blob from the XLS CFB container.codepage
is applied to BIFF2 - BIFF5 files without CodePage
records and to CSV files without BOM in type:"binary"
. BIFF8 XLS always defaults to 1200.PRN
affects parsing of text files without a common delimiter character._xlfn.
prefix, hidden from the user. SheetJS will strip _xlfn.
normally. The xlfn
option preserves them.WTF:true
forces those errors to be thrown.Strings can be interpreted in multiple ways. The type
parameter for read
tells the library how to parse the data argument:
type | expected input |
---|---|
"base64" | string: Base64 encoding of the file |
"binary" | string: binary string (byte n is data.charCodeAt(n) ) |
"string" | string: JS string (characters interpreted as UTF8) |
"buffer" | nodejs Buffer |
"array" | array: array of 8-bit unsigned int (byte n is data[n] ) |
"file" | string: path of file that will be read (nodejs only) |
Implementation Details (click to show)
Excel and other spreadsheet tools read the first few bytes and apply other heuristics to determine a file type. This enables file type punning: renaming files with the .xls
extension will tell your computer to use Excel to open the file but Excel will know how to handle it. This library applies similar logic:
Byte 0 | Raw File Type | Spreadsheet Types |
---|---|---|
0xD0 | CFB Container | BIFF 5/8 or protected XLSX/XLSB or WQ3/QPW or XLR |
0x09 | BIFF Stream | BIFF 2/3/4/5 |
0x3C | XML/HTML | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
0x50 | ZIP Archive | XLSB or XLSX/M or ODS or UOS2 or NUMBERS or text |
0x49 | Plain Text | SYLK or plain text |
0x54 | Plain Text | DIF or plain text |
0xEF | UTF8 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
0xFF | UTF16 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
0x00 | Record Stream | Lotus WK* or Quattro Pro or plain text |
0x7B | Plain text | RTF or plain text |
0x0A | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
0x0D | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
0x20 | Plain text | SpreadsheetML / Flat ODS / UOS1 / HTML / plain text |
DBF files are detected based on the first byte as well as the third and fourth bytes (corresponding to month and day of the file date)
Works for Windows files are detected based on the BOF record with type 0xFF
Plain text format guessing follows the priority order:
Format | Test |
---|---|
XML | <?xml appears in the first 1024 characters |
HTML | starts with < and HTML tags appear in the first 1024 characters * |
XML | starts with < and the first tag is valid |
RTF | starts with {\rt |
DSV | starts with /sep=.$/ , separator is the specified character |
DSV | more unquoted ` |
DSV | more unquoted ; chars than \t or , in the first 1024 |
TSV | more unquoted \t chars than , chars in the first 1024 |
CSV | one of the first 1024 characters is a comma "," |
ETH | starts with socialcalc:version: |
PRN | PRN option is set to true |
CSV | (fallback) |
html
, table
, head
, meta
, script
, style
, div
Why are random text files valid? (click to show)
Excel is extremely aggressive in reading files. Adding an XLS extension to any display text file (where the only characters are ANSI display chars) tricks Excel into thinking that the file is potentially a CSV or TSV file, even if it is only one column! This library attempts to replicate that behavior.
The best approach is to validate the desired worksheet and ensure it has the expected number of rows or columns. Extracting the range is extremely simple:
var range = XLSX.utils.decode_range(worksheet['!ref']);
var ncols = range.e.c - range.s.c + 1, nrows = range.e.r - range.s.r + 1;
The exported write
and writeFile
functions accept an options argument:
Option Name | Default | Description |
---|---|---|
type | Output data encoding (see Output Type below) | |
cellDates | false | Store dates as type d (default is n ) |
bookSST | false | Generate Shared String Table ** |
bookType | "xlsx" | Type of Workbook (see below for supported formats) |
sheet | "" | Name of Worksheet for single-sheet formats ** |
compression | false | Use ZIP compression for ZIP-based formats ** |
Props | Override workbook properties when writing ** | |
themeXLSX | Override theme XML when writing XLSX/XLSB/XLSM ** | |
ignoreEC | true | Suppress "number as text" errors ** |
bookSST
is slower and more memory intensive, but has better compatibility with older versions of iOS NumberscellDates
only applies to XLSX output and is not guaranteed to work with third-party readers. Excel itself does not usually write cells with type d
so non-Excel tools may ignore the data or error in the presence of dates.Props
is an object mirroring the workbook Props
field. See the table from the Workbook File Properties section.themeXLSX
will be saved as the primary theme for XLSX/XLSB/XLSM files (to xl/theme/theme1.xml
in the ZIP)ignoreEC
to false
to suppress.For broad compatibility with third-party tools, this library supports many output formats. The specific file type is controlled with bookType
option:
bookType | file ext | container | sheets | Description |
---|---|---|---|---|
xlsx | .xlsx | ZIP | multi | Excel 2007+ XML Format |
xlsm | .xlsm | ZIP | multi | Excel 2007+ Macro XML Format |
xlsb | .xlsb | ZIP | multi | Excel 2007+ Binary Format |
biff8 | .xls | CFB | multi | Excel 97-2004 Workbook Format |
biff5 | .xls | CFB | multi | Excel 5.0/95 Workbook Format |
biff4 | .xls | none | single | Excel 4.0 Worksheet Format |
biff3 | .xls | none | single | Excel 3.0 Worksheet Format |
biff2 | .xls | none | single | Excel 2.0 Worksheet Format |
xlml | .xls | none | multi | Excel 2003-2004 (SpreadsheetML) |
ods | .ods | ZIP | multi | OpenDocument Spreadsheet |
fods | .fods | none | multi | Flat OpenDocument Spreadsheet |
wk3 | .wk3 | none | single | Lotus Workbook (WK3) |
csv | .csv | none | single | Comma Separated Values |
txt | .txt | none | single | UTF-16 Unicode Text (TXT) |
sylk | .sylk | none | single | Symbolic Link (SYLK) |
html | .html | none | single | HTML Document |
dif | .dif | none | single | Data Interchange Format (DIF) |
dbf | .dbf | none | single | dBASE II + VFP Extensions (DBF) |
wk1 | .wk1 | none | single | Lotus Worksheet (WK1) |
rtf | .rtf | none | single | Rich Text Format (RTF) |
prn | .prn | none | single | Lotus Formatted Text |
eth | .eth | none | single | Ethercalc Record Format (ETH) |
compression
only applies to formats with ZIP containers.sheet
option specifying the worksheet. If the string is empty, the first worksheet is used.writeFile
will automatically guess the output file format based on the file extension if bookType
is not specified. It will choose the first format in the aforementioned table that matches the extension.The type
argument for write
mirrors the type
argument for read
:
type | output |
---|---|
"base64" | string: Base64 encoding of the file |
"binary" | string: binary string (byte n is data.charCodeAt(n) ) |
"string" | string: JS string (characters interpreted as UTF8) |
"buffer" | nodejs Buffer |
"array" | ArrayBuffer, fallback array of 8-bit unsigned int |
"file" | string: path of file that will be created (nodejs only) |
The sheet_to_*
functions accept a worksheet and an optional options object.
The *_to_sheet
functions accept a data object and an optional options object.
The examples are based on the following worksheet:
XXX| A | B | C | D | E | F | G |
---+---+---+---+---+---+---+---+
1 | S | h | e | e | t | J | S |
2 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
3 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
XLSX.utils.aoa_to_sheet
takes an array of arrays of JS values and returns a worksheet resembling the input data. Numbers, Booleans and Strings are stored as the corresponding styles. Dates are stored as date or numbers. Array holes and explicit undefined
values are skipped. null
values may be stubbed. All other values are stored as strings. The function takes an options argument:
Option Name | Default | Description |
---|---|---|
dateNF | FMT 14 | Use specified date format in string output |
cellDates | false | Store dates as type d (default is n ) |
sheetStubs | false | Create cell objects of type z for null values |
nullError | false | If true, emit #NULL! error cells for null values |
Examples (click to show)
To generate the example sheet:
var ws = XLSX.utils.aoa_to_sheet([
"SheetJS".split(""),
[1,2,3,4,5,6,7],
[2,3,4,5,6,7,8]
]);
XLSX.utils.sheet_add_aoa
takes an array of arrays of JS values and updates an existing worksheet object. It follows the same process as aoa_to_sheet
and accepts an options argument:
Option Name | Default | Description |
---|---|---|
dateNF | FMT 14 | Use specified date format in string output |
cellDates | false | Store dates as type d (default is n ) |
sheetStubs | false | Create cell objects of type z for null values |
nullError | false | If true, emit #NULL! error cells for null values |
origin | Use specified cell as starting point (see below) |
origin
is expected to be one of:
origin | Description |
---|---|
(cell object) | Use specified cell (cell object) |
(string) | Use specified cell (A1-style cell) |
(number >= 0) | Start from the first column at specified row (0-indexed) |
-1 | Append to bottom of worksheet starting on first column |
(default) | Start from cell A1 |
Examples (click to show)
Consider the worksheet:
XXX| A | B | C | D | E | F | G |
---+---+---+---+---+---+---+---+
1 | S | h | e | e | t | J | S |
2 | 1 | 2 | | | 5 | 6 | 7 |
3 | 2 | 3 | | | 6 | 7 | 8 |
4 | 3 | 4 | | | 7 | 8 | 9 |
5 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
This worksheet can be built up in the order A1:G1, A2:B4, E2:G4, A5:G5
:
/* Initial row */
var ws = XLSX.utils.aoa_to_sheet([ "SheetJS".split("") ]);
/* Write data starting at A2 */
XLSX.utils.sheet_add_aoa(ws, [[1,2], [2,3], [3,4]], {origin: "A2"});
/* Write data starting at E2 */
XLSX.utils.sheet_add_aoa(ws, [[5,6,7], [6,7,8], [7,8,9]], {origin:{r:1, c:4}});
/* Append row */
XLSX.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
XLSX.utils.json_to_sheet
takes an array of objects and returns a worksheet with automatically-generated "headers" based on the keys of the objects. The default column order is determined by the first appearance of the field using Object.keys
. The function accepts an options argument:
Option Name | Default | Description |
---|---|---|
header | Use specified field order (default Object.keys ) ** | |
dateNF | FMT 14 | Use specified date format in string output |
cellDates | false | Store dates as type d (default is n ) |
skipHeader | false | If true, do not include header row in output |
nullError | false | If true, emit #NULL! error cells for null values |
header
is an array and it does not contain a particular field, the key will be appended to the array.Date
object will generate a Date cell, while a string will generate a Text cell.nullError
is true, an error cell corresponding to #NULL!
will be written to the worksheet.Examples (click to show)
The original sheet cannot be reproduced using plain objects since JS object keys must be unique. After replacing the second e
and S
with e_1
and S_1
:
var ws = XLSX.utils.json_to_sheet([
{ S:1, h:2, e:3, e_1:4, t:5, J:6, S_1:7 },
{ S:2, h:3, e:4, e_1:5, t:6, J:7, S_1:8 }
], {header:["S","h","e","e_1","t","J","S_1"]});
Alternatively, the header row can be skipped:
var ws = XLSX.utils.json_to_sheet([
{ A:"S", B:"h", C:"e", D:"e", E:"t", F:"J", G:"S" },
{ A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7 },
{ A: 2, B: 3, C: 4, D: 5, E: 6, F: 7, G: 8 }
], {header:["A","B","C","D","E","F","G"], skipHeader:true});
XLSX.utils.sheet_add_json
takes an array of objects and updates an existing worksheet object. It follows the same process as json_to_sheet
and accepts an options argument:
Option Name | Default | Description |
---|---|---|
header | Use specified column order (default Object.keys ) | |
dateNF | FMT 14 | Use specified date format in string output |
cellDates | false | Store dates as type d (default is n ) |
skipHeader | false | If true, do not include header row in output |
nullError | false | If true, emit #NULL! error cells for null values |
origin | Use specified cell as starting point (see below) |
origin
is expected to be one of:
origin | Description |
---|---|
(cell object) | Use specified cell (cell object) |
(string) | Use specified cell (A1-style cell) |
(number >= 0) | Start from the first column at specified row (0-indexed) |
-1 | Append to bottom of worksheet starting on first column |
(default) | Start from cell A1 |
Examples (click to show)
Consider the worksheet:
XXX| A | B | C | D | E | F | G |
---+---+---+---+---+---+---+---+
1 | S | h | e | e | t | J | S |
2 | 1 | 2 | | | 5 | 6 | 7 |
3 | 2 | 3 | | | 6 | 7 | 8 |
4 | 3 | 4 | | | 7 | 8 | 9 |
5 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |
This worksheet can be built up in the order A1:G1, A2:B4, E2:G4, A5:G5
:
/* Initial row */
var ws = XLSX.utils.json_to_sheet([
{ A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" }
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true});
/* Write data starting at A2 */
XLSX.utils.sheet_add_json(ws, [
{ A: 1, B: 2 }, { A: 2, B: 3 }, { A: 3, B: 4 }
], {skipHeader: true, origin: "A2"});
/* Write data starting at E2 */
XLSX.utils.sheet_add_json(ws, [
{ A: 5, B: 6, C: 7 }, { A: 6, B: 7, C: 8 }, { A: 7, B: 8, C: 9 }
], {skipHeader: true, origin: { r: 1, c: 4 }, header: [ "A", "B", "C" ]});
/* Append row */
XLSX.utils.sheet_add_json(ws, [
{ A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 }
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true, origin: -1});
XLSX.utils.table_to_sheet
takes a table DOM element and returns a worksheet resembling the input table. Numbers are parsed. All other data will be stored as strings.
XLSX.utils.table_to_book
produces a minimal workbook based on the worksheet.
Both functions accept options arguments:
Option Name | Default | Description |
---|---|---|
raw | If true, every cell will hold raw strings | |
dateNF | FMT 14 | Use specified date format in string output |
cellDates | false | Store dates as type d (default is n ) |
sheetRows | 0 | If >0, read the first sheetRows rows of the table |
display | false | If true, hidden rows and cells will not be parsed |
Examples (click to show)
To generate the example sheet, start with the HTML table:
<table id="sheetjs">
<tr><td>S</td><td>h</td><td>e</td><td>e</td><td>t</td><td>J</td><td>S</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td></tr>
</table>
To process the table:
var tbl = document.getElementById('sheetjs');
var wb = XLSX.utils.table_to_book(tbl);
Note: XLSX.read
can handle HTML represented as strings.
XLSX.utils.sheet_add_dom
takes a table DOM element and updates an existing worksheet object. It follows the same process as table_to_sheet
and accepts an options argument:
Option Name | Default | Description |
---|---|---|
raw | If true, every cell will hold raw strings | |
dateNF | FMT 14 | Use specified date format in string output |
cellDates | false | Store dates as type d (default is n ) |
sheetRows | 0 | If >0, read the first sheetRows rows of the table |
display | false | If true, hidden rows and cells will not be parsed |
origin
is expected to be one of:
origin | Description |
---|---|
(cell object) | Use specified cell (cell object) |
(string) | Use specified cell (A1-style cell) |
(number >= 0) | Start from the first column at specified row (0-indexed) |
-1 | Append to bottom of worksheet starting on first column |
(default) | Start from cell A1 |
Examples (click to show)
A small helper function can create gap rows between tables:
function create_gap_rows(ws, nrows) {
var ref = XLSX.utils.decode_range(ws["!ref"]); // get original range
ref.e.r += nrows; // add to ending row
ws["!ref"] = XLSX.utils.encode_range(ref); // reassign row
}
/* first table */
var ws = XLSX.utils.table_to_sheet(document.getElementById('table1'));
create_gap_rows(ws, 1); // one row gap after first table
/* second table */
XLSX.utils.sheet_add_dom(ws, document.getElementById('table2'), {origin: -1});
create_gap_rows(ws, 3); // three rows gap after second table
/* third table */
XLSX.utils.sheet_add_dom(ws, document.getElementById('table3'), {origin: -1});
XLSX.utils.sheet_to_formulae
generates an array of commands that represent how a person would enter data into an application. Each entry is of the form A1-cell-address=formula-or-value
. String literals are prefixed with a '
in accordance with Excel.
Examples (click to show)
For the example sheet:
> var o = XLSX.utils.sheet_to_formulae(ws);
> [o[0], o[5], o[10], o[15], o[20]];
[ 'A1=\'S', 'F1=\'J', 'D2=4', 'B3=3', 'G3=8' ]
As an alternative to the writeFile
CSV type, XLSX.utils.sheet_to_csv
also produces CSV output. The function takes an options argument:
Option Name | Default | Description |
---|---|---|
FS | "," | "Field Separator" delimiter between fields |
RS | "\n" | "Record Separator" delimiter between rows |
dateNF | FMT 14 | Use specified date format in string output |
strip | false | Remove trailing field separators in each record ** |
blankrows | true | Include blank lines in the CSV output |
skipHidden | false | Skips hidden rows/columns in the CSV output |
forceQuotes | false | Force quotes around fields |
strip
will remove trailing commas from each line under default FS/RS
blankrows
must be set to false
to skip blank lines.forceQuotes
forces all cells to be wrapped in quotes.Examples (click to show)
For the example sheet:
> console.log(XLSX.utils.sheet_to_csv(ws));
S,h,e,e,t,J,S
1,2,3,4,5,6,7
2,3,4,5,6,7,8
> console.log(XLSX.utils.sheet_to_csv(ws, {FS:"\t"}));
S h e e t J S
1 2 3 4 5 6 7
2 3 4 5 6 7 8
> console.log(XLSX.utils.sheet_to_csv(ws,{FS:":",RS:"|"}));
S:h:e:e:t:J:S|1:2:3:4:5:6:7|2:3:4:5:6:7:8|
The txt
output type uses the tab character as the field separator. If the codepage
library is available (included in full distribution but not core), the output will be encoded in CP1200
and the BOM will be prepended.
XLSX.utils.sheet_to_txt
takes the same arguments as sheet_to_csv
.
As an alternative to the writeFile
HTML type, XLSX.utils.sheet_to_html
also produces HTML output. The function takes an options argument:
Option Name | Default | Description |
---|---|---|
id | Specify the id attribute for the TABLE element | |
editable | false | If true, set contenteditable="true" for every TD |
header | Override header (default html body ) | |
footer | Override footer (default /body /html ) |
Examples (click to show)
For the example sheet:
> console.log(XLSX.utils.sheet_to_html(ws));
// ...
XLSX.utils.sheet_to_json
generates different types of JS objects. The function takes an options argument:
Option Name | Default | Description |
---|---|---|
raw | true | Use raw values (true) or formatted strings (false) |
range | from WS | Override Range (see table below) |
header | Control output format (see table below) | |
dateNF | FMT 14 | Use specified date format in string output |
defval | Use specified value in place of null or undefined | |
blankrows | ** | Include blank lines in the output ** |
raw
only affects cells which have a format code (.z
) field or a formatted text (.w
) field.header
is specified, the first row is considered a data row; if header
is not specified, the first row is the header row and not considered data.header
is not specified, the conversion will automatically disambiguate header entries by affixing _
and a count starting at 1
. For example, if three columns have header foo
the output fields are foo
, foo_1
, foo_2
null
values are returned when raw
is true but are skipped when false.defval
is not specified, null and undefined values are skipped normally. If specified, all null and undefined points will be filled with defval
header
is 1
, the default is to generate blank rows. blankrows
must be set to false
to skip blank rows.header
is not 1
, the default is to skip blank rows. blankrows
must be true to generate blank rowsrange
is expected to be one of:
range | Description |
---|---|
(number) | Use worksheet range but set starting row to the value |
(string) | Use specified range (A1-style bounded range string) |
(default) | Use worksheet range (ws['!ref'] ) |
header
is expected to be one of:
header | Description |
---|---|
1 | Generate an array of arrays ("2D Array") |
"A" | Row object keys are literal column labels |
array of strings | Use specified strings as keys in row objects |
(default) | Read and disambiguate first row as keys |
If header is not 1
, the row object will contain the non-enumerable property __rowNum__
that represents the row of the sheet corresponding to the entry.
Examples (click to show)
For the example sheet:
> XLSX.utils.sheet_to_json(ws);
[ { S: 1, h: 2, e: 3, e_1: 4, t: 5, J: 6, S_1: 7 },
{ S: 2, h: 3, e: 4, e_1: 5, t: 6, J: 7, S_1: 8 } ]
> XLSX.utils.sheet_to_json(ws, {header:"A"});
[ { A: 'S', B: 'h', C: 'e', D: 'e', E: 't', F: 'J', G: 'S' },
{ A: '1', B: '2', C: '3', D: '4', E: '5', F: '6', G: '7' },
{ A: '2', B: '3', C: '4', D: '5', E: '6', F: '7', G: '8' } ]
> XLSX.utils.sheet_to_json(ws, {header:["A","E","I","O","U","6","9"]});
[ { '6': 'J', '9': 'S', A: 'S', E: 'h', I: 'e', O: 'e', U: 't' },
{ '6': '6', '9': '7', A: '1', E: '2', I: '3', O: '4', U: '5' },
{ '6': '7', '9': '8', A: '2', E: '3', I: '4', O: '5', U: '6' } ]
> XLSX.utils.sheet_to_json(ws, {header:1});
[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
[ '1', '2', '3', '4', '5', '6', '7' ],
[ '2', '3', '4', '5', '6', '7', '8' ] ]
Example showing the effect of raw
:
> ws['A2'].w = "3"; // set A2 formatted string value
> XLSX.utils.sheet_to_json(ws, {header:1, raw:false});
[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
[ '3', '2', '3', '4', '5', '6', '7' ], // <-- A2 uses the formatted string
[ '2', '3', '4', '5', '6', '7', '8' ] ]
> XLSX.utils.sheet_to_json(ws, {header:1});
[ [ 'S', 'h', 'e', 'e', 't', 'J', 'S' ],
[ 1, 2, 3, 4, 5, 6, 7 ], // <-- A2 uses the raw value
[ 2, 3, 4, 5, 6, 7, 8 ] ]
Despite the library name xlsx
, it supports numerous spreadsheet file formats:
Format | Read | Write |
---|---|---|
Excel Worksheet/Workbook Formats | :-----: | :-----: |
Excel 2007+ XML Formats (XLSX/XLSM) | ✔ | ✔ |
Excel 2007+ Binary Format (XLSB BIFF12) | ✔ | ✔ |
Excel 2003-2004 XML Format (XML "SpreadsheetML") | ✔ | ✔ |
Excel 97-2004 (XLS BIFF8) | ✔ | ✔ |
Excel 5.0/95 (XLS BIFF5) | ✔ | ✔ |
Excel 4.0 (XLS/XLW BIFF4) | ✔ | ✔ |
Excel 3.0 (XLS BIFF3) | ✔ | ✔ |
Excel 2.0/2.1 (XLS BIFF2) | ✔ | ✔ |
Excel Supported Text Formats | :-----: | :-----: |
Delimiter-Separated Values (CSV/TXT) | ✔ | ✔ |
Data Interchange Format (DIF) | ✔ | ✔ |
Symbolic Link (SYLK/SLK) | ✔ | ✔ |
Lotus Formatted Text (PRN) | ✔ | ✔ |
UTF-16 Unicode Text (TXT) | ✔ | ✔ |
Other Workbook/Worksheet Formats | :-----: | :-----: |
Numbers 3.0+ / iWork 2013+ Spreadsheet (NUMBERS) | ✔ | |
OpenDocument Spreadsheet (ODS) | ✔ | ✔ |
Flat XML ODF Spreadsheet (FODS) | ✔ | ✔ |
Uniform Office Format Spreadsheet (标文通 UOS1/UOS2) | ✔ | |
dBASE II/III/IV / Visual FoxPro (DBF) | ✔ | ✔ |
Lotus 1-2-3 (WK1/WK3) | ✔ | ✔ |
Lotus 1-2-3 (WKS/WK2/WK4/123) | ✔ | |
Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | ✔ | |
Works 1.x-3.x DOS / 2.x-5.x Windows Spreadsheet (WKS) | ✔ | |
Works 6.x-9.x Spreadsheet (XLR) | ✔ | |
Other Common Spreadsheet Output Formats | :-----: | :-----: |
HTML Tables | ✔ | ✔ |
Rich Text Format tables (RTF) | ✔ | |
Ethercalc Record Format (ETH) | ✔ | ✔ |
Features not supported by a given file format will not be written. Formats with range limits will be silently truncated:
Format | Last Cell | Max Cols | Max Rows |
---|---|---|---|
Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
Excel 4.0 (XLS BIFF4) | IV16384 | 256 | 16384 |
Excel 3.0 (XLS BIFF3) | IV16384 | 256 | 16384 |
Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
Lotus 1-2-3 R2 - R5 (WK1/WK3/WK4) | IV8192 | 256 | 8192 |
Lotus 1-2-3 R1 (WKS) | IV2048 | 256 | 2048 |
Excel 2003 SpreadsheetML range limits are governed by the version of Excel and are not enforced by the writer.
File Format Details (click to show)
Core Spreadsheet Formats
XLSX and XLSM files are ZIP containers containing a series of XML files in accordance with the Open Packaging Conventions (OPC). The XLSM format, almost identical to XLSX, is used for files containing macros.
The format is standardized in ECMA-376 and later in ISO/IEC 29500. Excel does not follow the specification, and there are additional documents discussing how Excel deviates from the specification.
BIFF 2/3 XLS are single-sheet streams of binary records. Excel 4 introduced the concept of a workbook (XLW
files) but also had single-sheet XLS
format. The structure is largely similar to the Lotus 1-2-3 file formats. BIFF5/8/12 extended the format in various ways but largely stuck to the same record format.
There is no official specification for any of these formats. Excel 95 can write files in these formats, so record lengths and fields were determined by writing in all of the supported formats and comparing files. Excel 2016 can generate BIFF5 files, enabling a full suite of file tests starting from XLSX or BIFF2.
BIFF8 exclusively uses the Compound File Binary container format, splitting some content into streams within the file. At its core, it still uses an extended version of the binary record format from older versions of BIFF.
The MS-XLS
specification covers the basics of the file format, and other specifications expand on serialization of features like properties.
Predating XLSX, SpreadsheetML files are simple XML files. There is no official and comprehensive specification, although MS has released documentation on the format. Since Excel 2016 can generate SpreadsheetML files, mapping features is pretty straightforward.
Introduced in parallel with XLSX, the XLSB format combines the BIFF architecture with the content separation and ZIP container of XLSX. For the most part nodes in an XLSX sub-file can be mapped to XLSB records in a corresponding sub-file.
The MS-XLSB
specification covers the basics of the file format, and other specifications expand on serialization of features like properties.
Excel CSV deviates from RFC4180 in a number of important ways. The generated CSV files should generally work in Excel although they may not work in RFC4180 compatible readers. The parser should generally understand Excel CSV. The writer proactively generates cells for formulae if values are unavailable.
Excel TXT uses tab as the delimiter and code page 1200.
Like in Excel, files starting with 0x49 0x44 ("ID")
are treated as Symbolic Link files. Unlike Excel, if the file does not have a valid SYLK header, it will be proactively reinterpreted as CSV. There are some files with semicolon delimiter that align with a valid SYLK file. For the broadest compatibility, all cells with the value of ID
are automatically wrapped in double-quotes.
Miscellaneous Workbook Formats
Support for other formats is generally far behind XLS/XLSB/XLSX support, due in part to a lack of publicly available documentation. Test files were produced in the respective apps and compared to their XLS exports to determine structure. The main focus is data extraction.
The Lotus formats consist of binary records similar to the BIFF structure. Lotus did release a specification decades ago covering the original WK1 format. Other features were deduced by producing files and comparing to Excel support.
Generated WK1 worksheets are compatible with Lotus 1-2-3 R2 and Excel 5.0.
Generated WK3 workbooks are compatible with Lotus 1-2-3 R9 and Excel 5.0.
The Quattro Pro formats use binary records in the same way as BIFF and Lotus. Some of the newer formats (namely WB3 and QPW) use a CFB enclosure just like BIFF8 XLS.
All versions of Works were limited to a single worksheet.
Works for DOS 1.x - 3.x and Works for Windows 2.x extends the Lotus WKS format with additional record types.
Works for Windows 3.x - 5.x uses the same format and WKS extension. The BOF record has type FF
Works for Windows 6.x - 9.x use the XLR format. XLR is nearly identical to BIFF8 XLS: it uses the CFB container with a Workbook stream. Works 9 saves the exact Workbook stream for the XLR and the 97-2003 XLS export. Works 6 XLS includes two empty worksheets but the main worksheet has an identical encoding. XLR also includes a WksSSWorkBook
stream similar to Lotus FM3/FMT files.
iWork 2013 (Numbers 3.0 / Pages 5.0 / Keynote 6.0) switched from a proprietary XML-based format to the current file format based on the iWork Archive (IWA). This format has been used up through the current release (Numbers 11.2).
The parser focuses on extracting raw data from tables. Numbers technically supports multiple tables in a logical worksheet, including custom titles. This parser will generate one worksheet per Numbers table.
ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to SpreadsheetML. Both are detailed in the OASIS standard, but tools like LO/OO add undocumented extensions. The parsers and writers do not implement the full standard, instead focusing on parts necessary to extract and store raw data.
UOS is a very similar format, and it comes in 2 varieties corresponding to ODS and FODS respectively. For the most part, the difference between the formats is in the names of tags and attributes.
Miscellaneous Worksheet Formats
Many older formats supported only one worksheet:
DBF is really a typed table format: each column can only hold one data type and each record omits type information. The parser generates a header row and inserts records starting at the second row of the worksheet. The writer makes files compatible with Visual FoxPro extensions.
Multi-file extensions like external memos and tables are currently unsupported, limited by the general ability to read arbitrary files in the web browser. The reader understands DBF Level 7 extensions like DATETIME.
There is no real documentation. All knowledge was gathered by saving files in various versions of Excel to deduce the meaning of fields. Notes:
Plain formulae are stored in the RC form.
Column widths are rounded to integral characters.
Lotus Formatted Text (PRN)
There is no real documentation, and in fact Excel treats PRN as an output-only file format. Nevertheless we can guess the column widths and reverse-engineer the original layout. Excel's 240 character width limitation is not enforced.
There is no unified definition. Visicalc DIF differs from Lotus DIF, and both differ from Excel DIF. Where ambiguous, the parser/writer follows the expected behavior from Excel. In particular, Excel extends DIF in incompatible ways:
Since Excel automatically converts numbers-as-strings to numbers, numeric string constants are converted to formulae: "0.3" -> "=""0.3""
DIF technically expects numeric cells to hold the raw numeric data, but Excel permits formatted numbers (including dates)
DIF technically has no support for formulae, but Excel will automatically convert plain formulae. Array formulae are not preserved.
HTML
Excel HTML worksheets include special metadata encoded in styles. For example, mso-number-format
is a localized string containing the number format. Despite the metadata the output is valid HTML, although it does accept bare &
symbols.
The writer adds type metadata to the TD elements via the t
tag. The parser looks for those tags and overrides the default interpretation. For example, text like <td>12345</td>
will be parsed as numbers but <td t="s">12345</td>
will be parsed as text.
Excel RTF worksheets are stored in clipboard when copying cells or ranges from a worksheet. The supported codes are a subset of the Word RTF support.
Ethercalc is an open source web spreadsheet powered by a record format reminiscent of SYLK wrapped in a MIME multi-part message.
(click to show)
make test
will run the node-based tests. By default it runs tests on files in every supported format. To test a specific file type, set FMTS
to the format you want to test. Feature-specific tests are available with make test_misc
$ make test_misc # run core tests
$ make test # run full tests
$ make test_xls # only use the XLS test files
$ make test_xlsx # only use the XLSX test files
$ make test_xlsb # only use the XLSB test files
$ make test_xml # only use the XML test files
$ make test_ods # only use the ODS test files
To enable all errors, set the environment variable WTF=1
:
$ make test # run full tests
$ WTF=1 make test # enable all error messages
flow
and eslint
checks are available:
$ make lint # eslint checks
$ make flow # make lint + Flow checking
$ make tslint # check TS definitions
(click to show)
The core in-browser tests are available at tests/index.html
within this repo. Start a local server and navigate to that directory to run the tests. make ctestserv
will start a server on port 8000.
make ctest
will generate the browser fixtures. To add more files, edit the tests/fixtures.lst
file and add the paths.
To run the full in-browser tests, clone the repo for oss.sheetjs.com
and replace the xlsx.js
file (then open a browser window and go to stress.html
):
$ cp xlsx.js ../SheetJS.github.io
$ cd ../SheetJS.github.io
$ simplehttpserver # or "python -mSimpleHTTPServer" or "serve"
$ open -a Chromium.app http://localhost:8000/stress.html
(click to show)
0.8
, 0.10
, 0.12
, 4.x
, 5.x
, 6.x
, 7.x
, 8.x
Tests utilize the mocha testing framework.
The test suite also includes tests for various time zones. To change the timezone locally, set the TZ environment variable:
$ env TZ="Asia/Kolkata" WTF=1 make test_misc
Test files are housed in another repo.
Running make init
will refresh the test_files
submodule and get the files. Note that this requires svn
, git
, hg
and other commands that may not be available. If make init
fails, please download the latest version of the test files snapshot from the repo
Latest Snapshot (click to show)
Latest test files snapshot: http://github.com/SheetJS/test_files/releases/download/20170409/test_files.zip
(download and unzip to the test_files
subdirectory)
Due to the precarious nature of the Open Specifications Promise, it is very important to ensure code is cleanroom. Contribution Notes
File organization (click to show)
At a high level, the final script is a concatenation of the individual files in the bits
folder. Running make
should reproduce the final output on all platforms. The README is similarly split into bits in the docbits
folder.
Folders:
folder | contents |
---|---|
bits | raw source files that make up the final script |
docbits | raw markdown files that make up README.md |
bin | server-side bin scripts (xlsx.njs ) |
dist | dist files for web browsers and nonstandard JS environments |
demos | demo projects for platforms like ExtendScript and Webpack |
tests | browser tests (run make ctest to rebuild) |
types | typescript definitions and tests |
misc | miscellaneous supporting scripts |
test_files | test files (pulled from the test files repository) |
After cloning the repo, running make help
will display a list of commands.
(click to show)
The xlsx.js
file is constructed from the files in the bits
subdirectory. The build script (run make
) will concatenate the individual bits to produce the script. Before submitting a contribution, ensure that running make will produce the xlsx.js
file exactly. The simplest way to test is to add the script:
$ git add xlsx.js
$ make clean
$ make
$ git diff xlsx.js
To produce the dist files, run make dist
. The dist files are updated in each version release and should not be committed between versions.
(click to show)
The included make.cmd
script will build xlsx.js
from the bits
directory. Building is as simple as:
> make
To prepare development environment:
> make init
The full list of commands available in Windows are displayed in make help
:
make init -- install deps and global modules
make lint -- run eslint linter
make test -- run mocha test suite
make misc -- run smaller test suite
make book -- rebuild README and summary
make help -- display this message
As explained in Test Files, on Windows the release ZIP file must be downloaded and extracted. If Bash on Windows is available, it is possible to run the OSX/Linux workflow. The following steps prepares the environment:
# Install support programs for the build and test commands
sudo apt-get install make git subversion mercurial
# Install nodejs and NPM within the WSL
wget -qO- https://deb.nodesource.com/setup_8.x | sudo bash
sudo apt-get install nodejs
# Install dev dependencies
sudo npm install -g mocha voc blanket xlsjs
(click to show)
The test_misc
target (make test_misc
on Linux/OSX / make misc
on Windows) runs the targeted feature tests. It should take 5-10 seconds to perform feature tests without testing against the entire test battery. New features should be accompanied with tests for the relevant file formats and features.
For tests involving the read side, an appropriate feature test would involve reading an existing file and checking the resulting workbook object. If a parameter is involved, files should be read with different values to verify that the feature is working as expected.
For tests involving a new write feature which can already be parsed, appropriate feature tests would involve writing a workbook with the feature and then opening and verifying that the feature is preserved.
For tests involving a new write feature without an existing read ability, please add a feature test to the kitchen sink tests/write.js
.
OSP-covered Specifications (click to show)
MS-CFB
: Compound File Binary File FormatMS-CTXLS
: Excel Custom Toolbar Binary File FormatMS-EXSPXML3
: Excel Calculation Version 2 Web Service XML SchemaMS-ODATA
: Open Data Protocol (OData)MS-ODRAW
: Office Drawing Binary File FormatMS-ODRAWXML
: Office Drawing Extensions to Office Open XML StructureMS-OE376
: Office Implementation Information for ECMA-376 Standards SupportMS-OFFCRYPTO
: Office Document Cryptography StructureMS-OI29500
: Office Implementation Information for ISO/IEC 29500 Standards SupportMS-OLEDS
: Object Linking and Embedding (OLE) Data StructuresMS-OLEPS
: Object Linking and Embedding (OLE) Property Set Data StructuresMS-OODF3
: Office Implementation Information for ODF 1.2 Standards SupportMS-OSHARED
: Office Common Data Types and Objects StructuresMS-OVBA
: Office VBA File Format StructureMS-XLDM
: Spreadsheet Data Model File FormatMS-XLS
: Excel Binary File Format (.xls) Structure SpecificationMS-XLSB
: Excel (.xlsb) Binary File FormatMS-XLSX
: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File FormatXLS
: Microsoft Office Excel 97-2007 Binary File Format SpecificationRTF
: Rich Text FormatAuthor: SheetJS
Source Code: https://github.com/SheetJS/sheetjs
License: Apache-2.0 License