diff --git a/docz/docs/02-installation/01-standalone.mdx b/docz/docs/02-installation/01-standalone.mdx index 5b50fde..0736474 100644 --- a/docz/docs/02-installation/01-standalone.mdx +++ b/docz/docs/02-installation/01-standalone.mdx @@ -24,7 +24,7 @@ The `latest` tag references the latest version and updates with each release: ``` -:::warning +:::warning A number of CDNs host older versions of the SheetJS libraries. Due to syncing issues, they are generally out of date. diff --git a/docz/docs/04-getting-started/03-demos/03-database.md b/docz/docs/04-getting-started/03-demos/03-database.md index 1cde595..d697d6a 100644 --- a/docz/docs/04-getting-started/03-demos/03-database.md +++ b/docz/docs/04-getting-started/03-demos/03-database.md @@ -311,8 +311,8 @@ var result = sql.all(); /* Loop across each name */ result.forEach(function(row) { /* Get first 100K rows */ - var aoo = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000").all(); - if(aoo.length > 0) { + var aoo = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000").all(); + if(aoo.length > 0) { /* Create Worksheet from the row objects */ var ws = XLSX.utils.json_to_sheet(aoo, {dense: true}); /* Add to Workbook */ @@ -361,8 +361,8 @@ var result = sql.all(); /* Loop across each name */ result.forEach(function(row) { /* Get first 100K rows */ - var aoo = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000").all(); - if(aoo.length > 0) { + var aoo = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000").all(); + if(aoo.length > 0) { /* Create Worksheet from the row objects */ var ws = XLSX.utils.json_to_sheet(aoo, {dense: true}); /* Add to Workbook */ @@ -804,9 +804,9 @@ const db = client.db(db_name); try { await db.collection('pres').drop(); } catch(e) {} const pres = db.collection('pres'); await pres.insertMany([ - { name: "Barack Obama", idx: 44 }, - { name: "Donald Trump", idx: 45 }, - { name: "Joseph Biden", idx: 46 } + { name: "Barack Obama", idx: 44 }, + { name: "Donald Trump", idx: 45 }, + { name: "Joseph Biden", idx: 46 } ], {ordered: true}); // highlight-start diff --git a/docz/docs/04-getting-started/03-demos/18-engines.md b/docz/docs/04-getting-started/03-demos/18-engines.md new file mode 100644 index 0000000..031e0ad --- /dev/null +++ b/docz/docs/04-getting-started/03-demos/18-engines.md @@ -0,0 +1,843 @@ +--- +sidebar_position: 18 +title: JavaScript Engines +--- + +import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +The most popular JavaScript engine is V8. Designed for embedding in software, +it powers Chrome, NodeJS, UXP, Deno and many other platforms and runtimes. + +There are many other runtimes with different design goals. Some are designed +for low-power or low-memory environments. Others aim for interoperability with +specific programming languages or environments. Typically they support a +superset of ES3 and are capable of running SheetJS code. + + +## General Caveats + +Common browser and NodeJS APIs are often missing from light-weight JS engines. + +**Global** + +Some engines do not provide `globalThis` or `global` or `window`. A `global` +variable can be exposed in one line that should be run in the JS engine: + +```js +var global = (function(){ return this; }).call(null); +``` + +**Console** + +Some engines do not provide a `console` object. `console.log` can be shimmed +using the engine functionality. For example, `hermes` provides `print()`: + +```js +var console = { log: function(x) { print(x); } }; +``` + +**Binary Data** + +Some engines do not provide easy ways of marshalling binary data. For example, +it is common to pass null-terminated arrays, which would truncate XLSX and XLS +files. APIs that accept pointers without length should be avoided. + +Base64 strings are safe for passing between JS and native code, but they should +only be used when there is no safe way to pass `ArrayBuffer` or `Uint8Array`. + + +## Duktape + +Duktape is an embeddable JS engine written in C. It has been ported to a number +of exotic architectures and operating systems. + +**Reading data** + +Duktape supports `Buffer` natively but should be sliced before processing: + +```c +/* parse a C char array as a workbook object */ +duk_push_external_buffer(ctx); +duk_config_buffer(ctx, -1, buf, len); +duk_put_global_string(ctx, "buf"); +duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); +``` + +**Writing data** + +`duk_get_buffer_data` can pull `Buffer` object data into the C code: + +```c +/* write a workbook object to a C char array */ +duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})"); +duk_size_t sz; +char *buf = (char *)duk_get_buffer_data(ctx, -1, sz); +duk_pop(ctx); +``` + +
Complete Example (click to show) + +:::note + +This demo was tested on macOS x64. + +::: + +0) Download and extract the latest release (2.7.0 at the time of writing) + +```bash +curl -LO https://duktape.org/duktape-2.7.0.tar.xz +tar -xJf duktape-2.7.0.tar.xz +mv duktape-2.7.0/src/*.{c,h} . +``` + +1) Download the standalone script, shim and test file: + + + +2) Save the following script to `sheetjs.duk.c`: + +```c title="sheetjs.duk.c" +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +#include +#include +#include +#include "duktape.h" + +#define FAIL_LOAD { \ + duk_push_undefined(ctx); \ + perror("Error in load_file"); \ + return 1; \ +} + +static char *read_file(const char *filename, size_t *sz) { + FILE *f = fopen(filename, "rb"); + if(!f) return NULL; + long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); } + char *buf = (char *)malloc(fsize * sizeof(char)); + *sz = fread((void *) buf, 1, fsize, f); + fclose(f); + return buf; +} + +static duk_int_t eval_file(duk_context *ctx, const char *filename) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) FAIL_LOAD + + duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len); + duk_int_t retval = duk_peval(ctx); + duk_pop(ctx); + return retval; +} + +static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) FAIL_LOAD + + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, buf, len); + duk_put_global_string(ctx, var); + return 0; +} + +static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) { + duk_get_global_string(ctx, var); + duk_size_t sz; + char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz); + + if(!buf) return 1; + FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f); + return 0; +} + +#define FAIL(cmd) { \ + printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \ + duk_destroy_heap(ctx); \ + return res; \ +} + +#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd); +int main(int argc, char *argv[]) { + duk_int_t res = 0; + + /* initialize */ + duk_context *ctx = duk_create_heap_default(); + /* duktape does not expose a standard "global" by default */ + DOIT("var global = (function(){ return this; }).call(null);"); + + /* load library */ + res = eval_file(ctx, "shim.min.js"); + if(res != 0) FAIL("shim load") + res = eval_file(ctx, "xlsx.full.min.js"); + if(res != 0) FAIL("library load") + + /* get version string */ + duk_eval_string(ctx, "XLSX.version"); + printf("SheetJS library version %s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); + + /* read file */ + res = load_file(ctx, argv[1], "buf"); + if(res != 0) FAIL("file load") + printf("Loaded file %s\n", argv[1]); + + /* parse workbook */ + DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});"); + DOIT("ws = wb.Sheets[wb.SheetNames[0]]"); + + /* print CSV */ + duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)"); + printf("%s\n", duk_get_string(ctx, -1)); + duk_pop(ctx); + + /* write file */ +#define WRITE_TYPE(BOOKTYPE) \ + DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\ + res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\ + if(res != 0) FAIL("save sheetjsw." BOOKTYPE) + + WRITE_TYPE("xlsb") + + /* cleanup */ + duk_destroy_heap(ctx); + return res; +} +``` + +3) Compile standalone `sheetjs.duk` binary + +```bash +gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm +``` + +4) Run the demo: + +```bash +./sheetjs.duk pres.numbers +``` + +If the program succeeded, the CSV contents will be printed to console and the +file `sheetjsw.xlsb` will be created. That file can be opened with Excel. + +
+ +## Goja + +Goja is a pure Go implementation of ECMAScript 5. It supports the standalone +scripts out of the box. + +**Reading data** + +Files can be read into `[]byte`: + +```go +/* read file */ +data, _ := ioutil.ReadFile("sheetjs.xlsx") +``` + +`[]byte` should be converted to an `ArrayBuffer` from Go: + +```go +/* load into engine */ +vm.Set("buf", vm.ToValue(vm.NewArrayBuffer(data))) + +/* parse */ +wb, _ = vm.RunString("wb = XLSX.read(buf, {type:'buffer'});") +``` + +**Writing data** + +`"base64"` strings can be decoded in Go: + +```go +/* write to base64 string */ +b64str, _ := vm.RunString("XLSX.write(wb, {type:'base64', bookType:'xlsx'})") + +/* pull data back into Go and write to file */ +buf, _ := base64.StdEncoding.DecodeString(b64str.String()) +_ = ioutil.WriteFile("sheetjs.xlsx", buf, 0644) +``` + +
Complete Example (click to show) + +0) Install Go + +1) Create a `go.mod` file and install dependencies: + +```bash +go mod init SheetGoja +go get github.com/dop251/goja +``` + +2) Download the standalone script and the shim: + + + +3) Save the following code to `SheetGoja.go`: + +```go title="SheetGoja.go" +package main + +import ( + b64 "encoding/base64" + "fmt" + "os" + "io/ioutil" + "github.com/dop251/goja" +) + +func safe_run_file(vm *goja.Runtime, file string) { + data, err := ioutil.ReadFile(file) + if err != nil { panic(err) } + src := string(data) + _, err = vm.RunString(src) + if err != nil { panic(err) } +} + +func eval_string(vm *goja.Runtime, cmd string) goja.Value { + v, err := vm.RunString(cmd) + if err != nil { panic(err) } + return v +} + +func write_type(vm *goja.Runtime, t string) { + b64str := eval_string(vm, "XLSX.write(wb, {type:'base64', bookType:'" + t + "'})") + buf, err := b64.StdEncoding.DecodeString(b64str.String()); + if err != nil { panic(err) } + err = ioutil.WriteFile("sheetjsg." + t, buf, 0644) + if err != nil { panic(err) } +} + +func main() { + vm := goja.New() + + /* initialize */ + eval_string(vm, "if(typeof global == 'undefined') global = (function(){ return this; }).call(null);") + + /* load library */ + safe_run_file(vm, "shim.min.js") + safe_run_file(vm, "xlsx.full.min.js") + + /* get version string */ + v := eval_string(vm, "XLSX.version") + fmt.Printf("SheetJS library version %s\n", v) + + /* read file */ + data, err := ioutil.ReadFile(os.Args[1]) + if err != nil { panic(err) } + vm.Set("buf", vm.ToValue(vm.NewArrayBuffer(data))) + fmt.Printf("Loaded file %s\n", os.Args[1]) + + /* parse workbook */ + eval_string(vm, "wb = XLSX.read(buf, {type:'buffer'});") + fmt.Printf("Parsed %s\n", os.Args[1]) + eval_string(vm, "ws = wb.Sheets[wb.SheetNames[0]]") + fmt.Printf("Grabbed %s\n", os.Args[1]) + + /* print CSV */ + csv := eval_string(vm, "XLSX.utils.sheet_to_csv(ws)") + fmt.Printf("%s\n", csv) + + /* write file */ + write_type(vm, "csv") +} +``` + +4) Build `SheetGoja`: + +```bash +go build SheetGoja.go +``` + +For testing, download and run + +```bash +./SheetGoja pres.numbers +``` + +This will print the contents as a CSV to screen AND write to `sheetjsg.csv` + +
+ + +## Hermes + +Hermes is an embeddable JS engine for React Native. The library and binary +distributions include a command-line tool `hermes` for running JS scripts. + +The simplest way to interact with the engine is to pass Base64 strings. The make +target builds a very simple payload with the data. + +:::note + +The official release includes the `hermes` standalone tool. While applications +should link against the official libraries, the standalone tool is useful for +verifying functionality. + +::: + +
Complete Example (click to show) + +Due to limitations of the standalone binary, this demo will encode a test file +as a Base64 string and directly add it to an amalgamated script. + +0) Install the `hermes` command line tool + +1) Download the standalone script, shim, and test file: + + + +2) Bundle the test file and create `payload.js`: + +```bash +node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')" +``` + +3) Create support scripts: + +- `global.js` creates a `global` variable and defines a fake `console`: + +```js title="global.js" +var global = (function(){ return this; }).call(null); +var console = { log: function(x) { print(x); } }; +``` + +- `hermes.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`: + +```js title="hermes.js" +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var wb = XLSX.read(payload, {type:'base64'}); +console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); +``` + +4) Create the amalgamation `xlsx.hermes.js`: + +```bash +cat global.js xlsx.full.min.js payload.js hermes.js > xlsx.hermes.js +``` + +The final script defines `global` before loading the standalone library. Once +ready, it will read the hardcoded test file and print the contents as CSV. + +5) Run the script using the Hermes standalone binary: + +``` +hermes xlsx.hermes.js +``` + +
+ +## JavaScriptCore + +:::warning Platform Limitations + +JavaScriptCore is primarily deployed in macOS and iOS applications. There is +some experimental support through the Bun runtime, but production applications +intending to support Windows / Linux / Android should try to embed V8. + +::: + +iOS and OSX ship with the JavaScriptCore framework for running JS scripts from +Swift and Objective-C. Hybrid function invocation is tricky, but explicit data +passing is straightforward. The demo shows a standalone Swift example for OSX. + +Binary strings can be passed back and forth using `String.Encoding.isoLatin1`. + +**Reading data** + +`String(contentsOf:encoding:)` reads from a path and returns an encoded string: + +```swift +/* read sheetjs.xls as base64 string */ +let file_path = shared_dir.appendingPathComponent("sheetjs.xls"); +let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1); +``` + +This string can be loaded into the JS engine and processed: + +```swift +/* load data in JSC */ +context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)); + +/* `payload` (the "forKeyedSubscript" parameter) is a binary string */ +context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});"); +``` + +**Writing data** + +When writing to binary string in JSC, the result should be stored in a variable +and stringified in Swift: + +```swift +/* write to binary string */ +context.evaluateScript("var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})"); + +/* `out` from the script is a binary string that can be stringified in Swift */ +let outvalue: JSValue! = context.objectForKeyedSubscript("out"); +var out: String! = outvalue.toString(); +``` + +`String#write(to:atomically:encoding)` writes the string to the specified path: + +```swift +/* write to sheetjsw.xlsx */ +let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx"); +try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1); +``` + +The demo includes a sample `SheetJSCore` Wrapper class to simplify operations. + +
Complete Example (click to show) + +:::caution This demo only runs on macOS + +This example requires macOS + Swift and will not work on Windows or Linux! + +::: + +0) Ensure Xcode is installed + +1) Download the standalone script, the shim and the test file: + + + +2) Download the Swift scripts for the demo + +- [`SheetJSCore.swift`](pathname:///swift/SheetJSCore.swift) Wrapper library +- [`main.swift`](pathname:///swift/main.swift) Command-line script + +3) Build the `SheetJSwift` binary: + +```bash +swiftc SheetJSCore.swift main.swift -o SheetJSwift +``` + +4) Test the program: + +```bash +./SheetJSwift pres.numbers +``` + +If successful, a CSV will be printed to console. The script also tries to write +to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers. + +
+ + +## QuickJS + +QuickJS is an embeddable JS engine written in C. It provides a separate set of +functions for interacting with the filesystem and the global object. It can run +the standalone browser scripts. + +
Complete Example (click to show) + +0) Ensure `quickjs` command line utility is installed + +1) Download the standalone script, the shim and the test file: + + + +2) Save the following script to `SheetJSQuick.js`: + +```js title="SheetJSQuick.js +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +/* load XLSX */ +import * as std from "std"; +globalThis.global = globalThis; +std.loadScript("xlsx.full.min.js"); + +/* read contents of file */ +var rh = std.open("pres.numbers", "rb"); +rh.seek(0, std.SEEK_END); +var sz = rh.tell(); +var ab = new ArrayBuffer(sz); +rh.seek(); +rh.read(ab, 0, sz); +rh.close(); + +/* parse file */ +var wb = XLSX.read(ab, {type: 'array'}); + +/* write array */ +var out = XLSX.write(wb, {type: 'array'}); + +/* write contents to file */ +var wh = std.open("SheetJSQuick.xlsx", "wb"); +wh.write(out, 0, out.byteLength); +wh.close(); +``` + +3) Test the program: + +```bash +quickjs SheetJSQuick.js +``` + +If successful, the script will generate `SheetJSQuick.xlsx`. + +
+ + +## Rhino + +Rhino is an ES3+ engine in Java. The `SheetJSRhino` class and `com.sheetjs` +package show a complete JAR deployment, including the full XLSX source. + +Due to code generation errors, optimization must be turned off: + +```java +Context context = Context.enter(); +context.setOptimizationLevel(-1); +``` + +
Complete Example (click to show) + +0) Download the appropriate Rhino build and rename to `rhino.jar` + +1) Download [`SheetJSRhino.zip`](pathname:///rhino/SheetJSRhino.zip) and unzip + +2) Save the following code to `SheetJSRhino.java`: + +```java title="SheetJSRhino.java" +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +/* vim: set ts=2: */ +import com.sheetjs.SheetJS; +import com.sheetjs.SheetJSFile; +import com.sheetjs.SheetJSSheet; + +public class SheetJSRhino { + public static void main(String args[]) throws Exception { + try { + SheetJS sjs = new SheetJS(); + + /* open file */ + SheetJSFile xl = sjs.read_file(args[0]); + + /* get sheetnames */ + String[] sheetnames = xl.get_sheet_names(); + System.err.println(sheetnames[0]); + + /* convert to CSV */ + SheetJSSheet sheet = xl.get_sheet(0); + String csv = sheet.get_csv(); + + System.out.println(csv); + + } catch(Exception e) { + throw e; + } finally { + SheetJS.close(); + } + } +} +``` + +3) Assemble `SheetJS.jar` from the demo code: + +```bash +javac -cp .:rhino.jar SheetJSRhino.java +jar -cf SheetJS.jar SheetJSRhino.class com/sheetjs/*.class +``` + +4) Download and test: + +```bash +java -cp .:SheetJS.jar:rhino.jar SheetJSRhino pres.xlsx +``` + +
+ +## Legacy Engines + +:::warning + +These examples were written when the engines were maintained. New projects +should not use these engines. The demos are included for legacy deployments. + +::: + +### ChakraCore + +:::caution + +ChakraCore was an open source JavaScript engine released by Microsoft. It was a +fork of the Chakra engine that powered Internet Explorer. When Microsoft Edge +switched to become a fork of Chromium, Microsoft stopped providing support. + +::: + +ChakraCore is an embeddable JS engine written in C++. The library and binary +distributions include a command-line tool `chakra` for running JS scripts. + +The simplest way to interact with the engine is to pass Base64 strings. The make +target builds a very simple payload with the data. + +:::note + +The official release includes the `ch` standalone binary. While applications +should link against the official libraries, the standalone tool is useful for +verifying functionality. + +::: + +
Complete Example (click to show) + +Due to limitations of the standalone binary, this demo will encode a test file +as a Base64 string and directly add it to an amalgamated script. + +0) Download and extract the ChakraCore release ZIP. Copy the binary (`bin/ch`) + to your project folder. + +1) Download the standalone script, shim, and test file: + + + +2) Bundle the test file and create `payload.js`: + +```bash +node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')" +``` + +3) Create support scripts: + +- `global.js` creates a `global` variable: + +```js title="global.js" +var global = (function(){ return this; }).call(null); +``` + +- `chakra.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`: + +```js title="chakra.js" +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var wb = XLSX.read(payload, {type:'base64'}); +console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); +``` + +4) Create the amalgamation `xlsx.chakra.js`: + +```bash +cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js +``` + +The final script defines `global` before loading the standalone library. Once +ready, it will read the hardcoded test file and print the contents as CSV. + +5) Run the script using the ChakraCore standalone binary: + +``` +./ch xlsx.chakra.js +``` + +
+ + +### Nashorn + +:::caution + +Nashorn shipped with Java 8. It was deprecated in Java 11 and was officially +removed in JDK 15. New Java applications should use [Rhino](#rhino). + +::: + + +Nashorn ships with Java. It includes a command-line tool `jjs` for running JS +scripts. It is somewhat limited but does offer access to the full Java runtime. + +The `load` function in `jjs` can load the minified source directly: + +```js +var global = (function(){ return this; }).call(null); +load('xlsx.full.min.js'); +``` + +The Java `nio` API provides the `Files.readAllBytes` method to read a file into +a byte array. To use in `XLSX.read`, the demo copies the bytes into a plain JS +array and calls `XLSX.read` with type `"array"`. + +
Complete Example (click to show) + +0) Ensure `jjs` is available on system path + +1) Download the standalone script, the shim and the test file: + + + +2) Save the following script to `SheetJSNashorn.js`: + +```js title="SheetJSNashorn.js" +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ + +/* load module */ +var global = (function(){ return this; }).call(null); +load('xlsx.full.min.js'); + +/* helper to convert byte array to plain JS array */ +function b2a(b) { + var out = new Array(b.length); + for(var i = 0; i < out.length; i++) out[i] = (b[i] < 0 ? b[i] + 256 : b[i]); + return out; +} + +function process_file(path) { + java.lang.System.out.println(path); + + /* read file */ + var path = java.nio.file.Paths.get(path); + var bytes = java.nio.file.Files.readAllBytes(path); + var u8a = b2a(bytes); + + /* read data */ + var wb = XLSX.read(u8a, {type:"array"}); + + /* get first worksheet as an array of arrays */ + var ws = wb.Sheets[wb.SheetNames[0]]; + var js = XLSX.utils.sheet_to_json(ws, {header:1}); + + /* print out every line */ + js.forEach(function(l) { java.lang.System.out.println(JSON.stringify(l)); }); +} + +process_file('pres.numbers'); +``` + +3) Test the script: + +```bash +jjs SheetJSNashorn.js +``` + +It will print out the first worksheet contents. + +
diff --git a/docz/docs/04-getting-started/03-demos/index.md b/docz/docs/04-getting-started/03-demos/index.md index 657ed1e..0c67991 100644 --- a/docz/docs/04-getting-started/03-demos/index.md +++ b/docz/docs/04-getting-started/03-demos/index.md @@ -45,7 +45,7 @@ The demo projects include small runnable examples and short explainers. - [`SalesForce Lightning Web Components`](./salesforce) - [`Excel JavaScript API`](./excel) - [`Headless Automation`](./headless) -- [`Other JavaScript Engines`](https://github.com/SheetJS/SheetJS/tree/master/demos/altjs/) +- [`Other JavaScript Engines`](./engines) - [`"serverless" functions`](https://github.com/SheetJS/SheetJS/tree/master/demos/function/) - [`Databases and Structured Data Stores`](./database) - [`NoSQL, K/V, and Unstructured Data Stores`](./nosql) diff --git a/docz/docs/06-solutions/05-output.md b/docz/docs/06-solutions/05-output.md index eff1b46..0b0d09f 100644 --- a/docz/docs/06-solutions/05-output.md +++ b/docz/docs/06-solutions/05-output.md @@ -898,13 +898,13 @@ import {utils, stream, set_cptable} from 'https://cdn.sheetjs.com/xlsx-latest/pa /* `Readable` will be compatible with how SheetJS uses `stream.Readable` */ function NodeReadableCB(cb:(d:any)=>void) { - var rd = { - __done: false, - _read: function() {}, - push: function(d: any) { if(!this.__done) cb(d); if(d == null) this.__done = true; }, - resume: function pump() {for(var i = 0; i < 10000 && !this.__done; ++i) rd._read(); if(!rd.__done) setTimeout(pump, 0); } - }; - return rd; + var rd = { + __done: false, + _read: function() {}, + push: function(d: any) { if(!this.__done) cb(d); if(d == null) this.__done = true; }, + resume: function pump() {for(var i = 0; i < 10000 && !this.__done; ++i) rd._read(); if(!rd.__done) setTimeout(pump, 0); } + }; + return rd; } function NodeReadable(rd: any) { return function() { return rd; }; } /* The callback gets each CSV row. It will be `null` when the stream is drained */ diff --git a/docz/docs/07-csf/01-general.md b/docz/docs/07-csf/01-general.md index d88f984..40ce9e6 100644 --- a/docz/docs/07-csf/01-general.md +++ b/docz/docs/07-csf/01-general.md @@ -1,11 +1,8 @@ --- sidebar_position: 1 +title: Addresses and Ranges --- -# Addresses and Ranges - -The "Common Spreadsheet Format" (CSF) is the object model used by SheetJS. - ## Cell Addresses Cell address objects are stored as `{c:C, r:R}` where `C` and `R` are 0-indexed diff --git a/docz/docs/07-csf/_category_.json b/docz/docs/07-csf/_category_.json index c73cfc9..fc2c79c 100644 --- a/docz/docs/07-csf/_category_.json +++ b/docz/docs/07-csf/_category_.json @@ -1,4 +1,4 @@ { - "label": "Common Spreadsheet Format", + "label": "CSF Object Model", "position": 7 } diff --git a/docz/docs/07-csf/index.md b/docz/docs/07-csf/index.md new file mode 100644 index 0000000..3d024fc --- /dev/null +++ b/docz/docs/07-csf/index.md @@ -0,0 +1,23 @@ +--- +hide_table_of_contents: true +title: Common Spreadsheet Format +--- + +import DocCardList from '@theme/DocCardList'; +import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; + +The "Common Spreadsheet Format" (CSF) is the object model used by SheetJS. This +section covers the JS representation of workbooks, worksheets, cells, ranges, +addresses and other features. + +### Contents + + \ No newline at end of file diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js index dc49c26..beb22a4 100644 --- a/docz/docusaurus.config.js +++ b/docz/docusaurus.config.js @@ -142,6 +142,7 @@ const config = { prism: { theme: lightCodeTheme, darkTheme: darkCodeTheme, + additionalLanguages: [ "swift", "java" ], }, liveCodeBlock: { playgroundPosition: 'top' diff --git a/docz/static/browserify/app.js b/docz/static/browserify/app.js index ea0de8e..8590e78 100644 --- a/docz/static/browserify/app.js +++ b/docz/static/browserify/app.js @@ -6,143 +6,143 @@ var XLSX = require('xlsx'); var global_wb; var process_wb = (function() { - var OUT = document.getElementById('out'); - var HTMLOUT = document.getElementById('htmlout'); + var OUT = document.getElementById('out'); + var HTMLOUT = document.getElementById('htmlout'); - var get_format = (function() { - var radios = document.getElementsByName( "format" ); - return function() { - for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value; - }; - })(); + var get_format = (function() { + var radios = document.getElementsByName( "format" ); + return function() { + for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value; + }; + })(); - var to_json = function to_json(workbook) { - var result = {}; - workbook.SheetNames.forEach(function(sheetName) { - var roa = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); - if(roa.length) result[sheetName] = roa; - }); - return JSON.stringify(result, 2, 2); - }; + var to_json = function to_json(workbook) { + var result = {}; + workbook.SheetNames.forEach(function(sheetName) { + var roa = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); + if(roa.length) result[sheetName] = roa; + }); + return JSON.stringify(result, 2, 2); + }; - var to_csv = function to_csv(workbook) { - var result = []; - workbook.SheetNames.forEach(function(sheetName) { - var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); - if(csv.length){ - result.push("SHEET: " + sheetName); - result.push(""); - result.push(csv); - } - }); - return result.join("\n"); - }; + var to_csv = function to_csv(workbook) { + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); + if(csv.length){ + result.push("SHEET: " + sheetName); + result.push(""); + result.push(csv); + } + }); + return result.join("\n"); + }; - var to_fmla = function to_fmla(workbook) { - var result = []; - workbook.SheetNames.forEach(function(sheetName) { - var formulae = XLSX.utils.get_formulae(workbook.Sheets[sheetName]); - if(formulae.length){ - result.push("SHEET: " + sheetName); - result.push(""); - result.push(formulae.join("\n")); - } - }); - return result.join("\n"); - }; + var to_fmla = function to_fmla(workbook) { + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var formulae = XLSX.utils.get_formulae(workbook.Sheets[sheetName]); + if(formulae.length){ + result.push("SHEET: " + sheetName); + result.push(""); + result.push(formulae.join("\n")); + } + }); + return result.join("\n"); + }; - var to_html = function to_html(workbook) { - HTMLOUT.innerHTML = ""; - workbook.SheetNames.forEach(function(sheetName) { - var htmlstr = XLSX.write(workbook, {sheet:sheetName, type:'string', bookType:'html'}); - HTMLOUT.innerHTML += htmlstr; - }); - return ""; - }; + var to_html = function to_html(workbook) { + HTMLOUT.innerHTML = ""; + workbook.SheetNames.forEach(function(sheetName) { + var htmlstr = XLSX.write(workbook, {sheet:sheetName, type:'string', bookType:'html'}); + HTMLOUT.innerHTML += htmlstr; + }); + return ""; + }; - return function process_wb(wb) { - global_wb = wb; - var output = ""; - switch(get_format()) { - case "form": output = to_fmla(wb); break; - case "html": output = to_html(wb); break; - case "json": output = to_json(wb); break; - default: output = to_csv(wb); - } - if(OUT.innerText === undefined) OUT.textContent = output; - else OUT.innerText = output; - if(typeof console !== 'undefined') console.log("output", new Date()); - }; + return function process_wb(wb) { + global_wb = wb; + var output = ""; + switch(get_format()) { + case "form": output = to_fmla(wb); break; + case "html": output = to_html(wb); break; + case "json": output = to_json(wb); break; + default: output = to_csv(wb); + } + if(OUT.innerText === undefined) OUT.textContent = output; + else OUT.innerText = output; + if(typeof console !== 'undefined') console.log("output", new Date()); + }; })(); var setfmt = window.setfmt = function setfmt() { if(global_wb) process_wb(global_wb); }; var b64it = window.b64it = (function() { - var tarea = document.getElementById('b64data'); - return function b64it() { - if(typeof console !== 'undefined') console.log("onload", new Date()); - var wb = XLSX.read(tarea.value, {type:'base64', WTF:false}); - process_wb(wb); - }; + var tarea = document.getElementById('b64data'); + return function b64it() { + if(typeof console !== 'undefined') console.log("onload", new Date()); + var wb = XLSX.read(tarea.value, {type:'base64', WTF:false}); + process_wb(wb); + }; })(); var do_file = (function() { - var use_worker = typeof Worker !== 'undefined'; - var domwork = document.getElementsByName("useworker")[0]; - if(!use_worker) domwork.disabled = !(domwork.checked = false); + var use_worker = typeof Worker !== 'undefined'; + var domwork = document.getElementsByName("useworker")[0]; + if(!use_worker) domwork.disabled = !(domwork.checked = false); - var xw = function xw(data, cb) { - var worker = new Worker('./worker.js'); - worker.onmessage = function(e) { - switch(e.data.t) { - case 'ready': break; - case 'e': console.error(e.data.d); break; - case 'xlsx': cb(JSON.parse(e.data.d)); break; - } - }; - worker.postMessage({d:data,b:'array'}); - }; + var xw = function xw(data, cb) { + var worker = new Worker('./worker.js'); + worker.onmessage = function(e) { + switch(e.data.t) { + case 'ready': break; + case 'e': console.error(e.data.d); break; + case 'xlsx': cb(JSON.parse(e.data.d)); break; + } + }; + worker.postMessage({d:data,b:'array'}); + }; - return function do_file(files) { - use_worker = domwork.checked; - var f = files[0]; - var reader = new FileReader(); - reader.onload = function(e) { - if(typeof console !== 'undefined') console.log("onload", new Date(), use_worker); - var data = e.target.result; - data = new Uint8Array(data); - if(use_worker) xw(data, process_wb); - else process_wb(XLSX.read(data, {type: 'array'})); - }; - reader.readAsArrayBuffer(f); - }; + return function do_file(files) { + use_worker = domwork.checked; + var f = files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + if(typeof console !== 'undefined') console.log("onload", new Date(), use_worker); + var data = e.target.result; + data = new Uint8Array(data); + if(use_worker) xw(data, process_wb); + else process_wb(XLSX.read(data, {type: 'array'})); + }; + reader.readAsArrayBuffer(f); + }; })(); (function() { - var drop = document.getElementById('drop'); - if(!drop.addEventListener) return; + var drop = document.getElementById('drop'); + if(!drop.addEventListener) return; - function handleDrop(e) { - e.stopPropagation(); - e.preventDefault(); - do_file(e.dataTransfer.files); - } + function handleDrop(e) { + e.stopPropagation(); + e.preventDefault(); + do_file(e.dataTransfer.files); + } - function handleDragover(e) { - e.stopPropagation(); - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - } + function handleDragover(e) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + } - drop.addEventListener('dragenter', handleDragover, false); - drop.addEventListener('dragover', handleDragover, false); - drop.addEventListener('drop', handleDrop, false); + drop.addEventListener('dragenter', handleDragover, false); + drop.addEventListener('dragover', handleDragover, false); + drop.addEventListener('drop', handleDrop, false); })(); (function() { - var xlf = document.getElementById('xlf'); - if(!xlf.addEventListener) return; - function handleFile(e) { do_file(e.target.files); } - xlf.addEventListener('change', handleFile, false); + var xlf = document.getElementById('xlf'); + if(!xlf.addEventListener) return; + function handleFile(e) { do_file(e.target.files); } + xlf.addEventListener('change', handleFile, false); })(); diff --git a/docz/static/browserify/index.html b/docz/static/browserify/index.html index 010e5aa..453c59a 100644 --- a/docz/static/browserify/index.html +++ b/docz/static/browserify/index.html @@ -7,16 +7,16 @@ SheetJS Live Demo @@ -48,15 +48,15 @@ Use Web Workers: (when available) diff --git a/docz/static/cdg/index.html b/docz/static/cdg/index.html index 055c3cf..1cf2a45 100644 --- a/docz/static/cdg/index.html +++ b/docz/static/cdg/index.html @@ -7,16 +7,16 @@ SheetJS + canvas-datagrid Live Demo @@ -51,117 +51,117 @@ a { text-decoration: none } var cDg; var process_wb = (function() { - var XPORT = document.getElementById('xport'); - var HTMLOUT = document.getElementById('htmlout'); + var XPORT = document.getElementById('xport'); + var HTMLOUT = document.getElementById('htmlout'); - return function process_wb(wb) { - /* get data */ - var ws = wb.Sheets[wb.SheetNames[0]]; - var data = XLSX.utils.sheet_to_json(ws, {header:1}); + return function process_wb(wb) { + /* get data */ + var ws = wb.Sheets[wb.SheetNames[0]]; + var data = XLSX.utils.sheet_to_json(ws, {header:1}); - /* update canvas-datagrid */ - if(!cDg) cDg = canvasDatagrid({ parentNode:HTMLOUT, data:data }); - cDg.style.height = '100%'; - cDg.style.width = '100%'; - cDg.data = data; - XPORT.disabled = false; + /* update canvas-datagrid */ + if(!cDg) cDg = canvasDatagrid({ parentNode:HTMLOUT, data:data }); + cDg.style.height = '100%'; + cDg.style.width = '100%'; + cDg.data = data; + XPORT.disabled = false; - /* create schema (for A,B,C column headings) */ - var range = XLSX.utils.decode_range(ws['!ref']); - for(var i = range.s.c; i <= range.e.c; ++i) cDg.schema[i - range.s.c].title = XLSX.utils.encode_col(i); + /* create schema (for A,B,C column headings) */ + var range = XLSX.utils.decode_range(ws['!ref']); + for(var i = range.s.c; i <= range.e.c; ++i) cDg.schema[i - range.s.c].title = XLSX.utils.encode_col(i); - HTMLOUT.style.height = (window.innerHeight - 400) + "px"; - HTMLOUT.style.width = (window.innerWidth - 50) + "px"; + HTMLOUT.style.height = (window.innerHeight - 400) + "px"; + HTMLOUT.style.width = (window.innerWidth - 50) + "px"; - if(typeof console !== 'undefined') console.log("output", new Date()); - }; + if(typeof console !== 'undefined') console.log("output", new Date()); + }; })(); var do_file = (function() { - return function do_file(files) { - var f = files[0]; - var reader = new FileReader(); - reader.onload = function(e) { - if(typeof console !== 'undefined') console.log("onload", new Date()); - var data = e.target.result; - data = new Uint8Array(data); - process_wb(XLSX.read(data, {type: 'array'})); - }; - reader.readAsArrayBuffer(f); - }; + return function do_file(files) { + var f = files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + if(typeof console !== 'undefined') console.log("onload", new Date()); + var data = e.target.result; + data = new Uint8Array(data); + process_wb(XLSX.read(data, {type: 'array'})); + }; + reader.readAsArrayBuffer(f); + }; })(); (function() { - var drop = document.getElementById('drop'); - if(!drop.addEventListener) return; + var drop = document.getElementById('drop'); + if(!drop.addEventListener) return; - function handleDrop(e) { - e.stopPropagation(); - e.preventDefault(); - do_file(e.dataTransfer.files); - } + function handleDrop(e) { + e.stopPropagation(); + e.preventDefault(); + do_file(e.dataTransfer.files); + } - function handleDragover(e) { - e.stopPropagation(); - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - } + function handleDragover(e) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + } - drop.addEventListener('dragenter', handleDragover, false); - drop.addEventListener('dragover', handleDragover, false); - drop.addEventListener('drop', handleDrop, false); + drop.addEventListener('dragenter', handleDragover, false); + drop.addEventListener('dragover', handleDragover, false); + drop.addEventListener('drop', handleDrop, false); })(); (function() { - var xlf = document.getElementById('xlf'); - if(!xlf.addEventListener) return; - function handleFile(e) { do_file(e.target.files); } - xlf.addEventListener('change', handleFile, false); + var xlf = document.getElementById('xlf'); + if(!xlf.addEventListener) return; + function handleFile(e) { do_file(e.target.files); } + xlf.addEventListener('change', handleFile, false); })(); var export_xlsx = (function() { - function prep(arr) { - var out = []; - for(var i = 0; i < arr.length; ++i) { - if(!arr[i]) continue; - if(Array.isArray(arr[i])) { out[i] = arr[i]; continue }; - var o = new Array(); - Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] }); - out[i] = o; - } - return out; - } + function prep(arr) { + var out = []; + for(var i = 0; i < arr.length; ++i) { + if(!arr[i]) continue; + if(Array.isArray(arr[i])) { out[i] = arr[i]; continue }; + var o = new Array(); + Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] }); + out[i] = o; + } + return out; + } - return function export_xlsx() { - if(!cDg) return; - /* convert canvas-datagrid data to worksheet */ - var new_ws = XLSX.utils.aoa_to_sheet(prep(cDg.data)); + return function export_xlsx() { + if(!cDg) return; + /* convert canvas-datagrid data to worksheet */ + var new_ws = XLSX.utils.aoa_to_sheet(prep(cDg.data)); - /* build workbook */ - var new_wb = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS'); + /* build workbook */ + var new_wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS'); - /* write file and trigger a download */ - XLSX.writeFile(new_wb, 'SheetJSCanvasDataGridExport.xlsx', {bookSST:true}); - }; + /* write file and trigger a download */ + XLSX.writeFile(new_wb, 'SheetJSCanvasDataGridExport.xlsx', {bookSST:true}); + }; })(); (async() => { - const ab = await(await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); - process_wb(XLSX.read(ab)); + const ab = await(await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); + process_wb(XLSX.read(ab)); })(); diff --git a/docz/static/cli/xlsx-cli.js b/docz/static/cli/xlsx-cli.js index 7c3255b..51c248f 100644 --- a/docz/static/cli/xlsx-cli.js +++ b/docz/static/cli/xlsx-cli.js @@ -4,113 +4,113 @@ var X = require('xlsx'); try { require('exit-on-epipe'); } catch(e) {} var fs = require('fs'), program; try { program = require('commander'); } catch(e) { - [ - "The `xlsx` command line tool is deprecated in favor of `xlsx-cli`.", - "", - "For new versions of node, we recommend using `npx`:", - " $ npx xlsx-cli --help", - "", - "For older versions of node, explicitly install `xlsx-cli` globally:", - " $ npm i -g xlsx-cli", - " $ xlsx-cli --help" - ].forEach(function(m) { console.error(m); }); - process.exit(1); + [ + "The `xlsx` command line tool is deprecated in favor of `xlsx-cli`.", + "", + "For new versions of node, we recommend using `npx`:", + " $ npx xlsx-cli --help", + "", + "For older versions of node, explicitly install `xlsx-cli` globally:", + " $ npm i -g xlsx-cli", + " $ xlsx-cli --help" + ].forEach(function(m) { console.error(m); }); + process.exit(1); } program - .version(X.version) - .usage('[options] [sheetname]') - .option('-f, --file ', 'use specified workbook') - .option('-s, --sheet ', 'print specified sheet (default first sheet)') - .option('-N, --sheet-index ', 'use specified sheet index (0-based)') - .option('-p, --password ', 'if file is encrypted, try with specified pw') - .option('-l, --list-sheets', 'list sheet names and exit') - .option('-o, --output ', 'output to specified file') + .version(X.version) + .usage('[options] [sheetname]') + .option('-f, --file ', 'use specified workbook') + .option('-s, --sheet ', 'print specified sheet (default first sheet)') + .option('-N, --sheet-index ', 'use specified sheet index (0-based)') + .option('-p, --password ', 'if file is encrypted, try with specified pw') + .option('-l, --list-sheets', 'list sheet names and exit') + .option('-o, --output ', 'output to specified file') - .option('-B, --xlsb', 'emit XLSB to or .xlsb') - .option('-M, --xlsm', 'emit XLSM to or .xlsm') - .option('-X, --xlsx', 'emit XLSX to or .xlsx') - .option('-I, --xlam', 'emit XLAM to or .xlam') - .option('-Y, --ods', 'emit ODS to or .ods') - .option('-8, --xls', 'emit XLS to or .xls (BIFF8)') - .option('-5, --biff5','emit XLS to or .xls (BIFF5)') - .option('-4, --biff4','emit XLS to or .xls (BIFF4)') - .option('-3, --biff3','emit XLS to or .xls (BIFF3)') - .option('-2, --biff2','emit XLS to or .xls (BIFF2)') - .option('-i, --xla', 'emit XLA to or .xla') - .option('-6, --xlml', 'emit SSML to or .xls (2003 XML)') - .option('-T, --fods', 'emit FODS to or .fods (Flat ODS)') - .option('--wk3', 'emit WK3 to or .txt (Lotus WK3)') - .option('--numbers', 'emit NUMBERS to or .numbers') + .option('-B, --xlsb', 'emit XLSB to or .xlsb') + .option('-M, --xlsm', 'emit XLSM to or .xlsm') + .option('-X, --xlsx', 'emit XLSX to or .xlsx') + .option('-I, --xlam', 'emit XLAM to or .xlam') + .option('-Y, --ods', 'emit ODS to or .ods') + .option('-8, --xls', 'emit XLS to or .xls (BIFF8)') + .option('-5, --biff5','emit XLS to or .xls (BIFF5)') + .option('-4, --biff4','emit XLS to or .xls (BIFF4)') + .option('-3, --biff3','emit XLS to or .xls (BIFF3)') + .option('-2, --biff2','emit XLS to or .xls (BIFF2)') + .option('-i, --xla', 'emit XLA to or .xla') + .option('-6, --xlml', 'emit SSML to or .xls (2003 XML)') + .option('-T, --fods', 'emit FODS to or .fods (Flat ODS)') + .option('--wk3', 'emit WK3 to or .txt (Lotus WK3)') + .option('--numbers', 'emit NUMBERS to or .numbers') - .option('-S, --formulae', 'emit list of values and formulae') - .option('-j, --json', 'emit formatted JSON (all fields text)') - .option('-J, --raw-js', 'emit raw JS object (raw numbers)') - .option('-A, --arrays', 'emit rows as JS objects (raw numbers)') - .option('-H, --html', 'emit HTML to or .html') - .option('-D, --dif', 'emit DIF to or .dif (Lotus DIF)') - .option('-U, --dbf', 'emit DBF to or .dbf (MSVFP DBF)') - .option('-K, --sylk', 'emit SYLK to or .slk (Excel SYLK)') - .option('-P, --prn', 'emit PRN to or .prn (Lotus PRN)') - .option('-E, --eth', 'emit ETH to or .eth (Ethercalc)') - .option('-t, --txt', 'emit TXT to or .txt (UTF-8 TSV)') - .option('-r, --rtf', 'emit RTF to or .txt (Table RTF)') - .option('--wk1', 'emit WK1 to or .txt (Lotus WK1)') - .option('-z, --dump', 'dump internal representation as JSON') - .option('--props', 'dump workbook properties as CSV') + .option('-S, --formulae', 'emit list of values and formulae') + .option('-j, --json', 'emit formatted JSON (all fields text)') + .option('-J, --raw-js', 'emit raw JS object (raw numbers)') + .option('-A, --arrays', 'emit rows as JS objects (raw numbers)') + .option('-H, --html', 'emit HTML to or .html') + .option('-D, --dif', 'emit DIF to or .dif (Lotus DIF)') + .option('-U, --dbf', 'emit DBF to or .dbf (MSVFP DBF)') + .option('-K, --sylk', 'emit SYLK to or .slk (Excel SYLK)') + .option('-P, --prn', 'emit PRN to or .prn (Lotus PRN)') + .option('-E, --eth', 'emit ETH to or .eth (Ethercalc)') + .option('-t, --txt', 'emit TXT to or .txt (UTF-8 TSV)') + .option('-r, --rtf', 'emit RTF to or .txt (Table RTF)') + .option('--wk1', 'emit WK1 to or .txt (Lotus WK1)') + .option('-z, --dump', 'dump internal representation as JSON') + .option('--props', 'dump workbook properties as CSV') - .option('-F, --field-sep ', 'CSV field separator', ",") - .option('-R, --row-sep ', 'CSV row separator', "\n") - .option('-n, --sheet-rows ', 'Number of rows to process (0=all rows)') - .option('--codepage ', 'default to specified codepage when ambiguous') - .option('--sst', 'generate shared string table for XLS* formats') - .option('--compress', 'use compression when writing XLSX/M/B and ODS') - .option('--read', 'read but do not generate output') - .option('--book', 'for single-sheet formats, emit a file per worksheet') - .option('--all', 'parse everything; write as much as possible') - .option('--dev', 'development mode') - .option('--sparse', 'sparse mode') - .option('-q, --quiet', 'quiet mode'); + .option('-F, --field-sep ', 'CSV field separator', ",") + .option('-R, --row-sep ', 'CSV row separator', "\n") + .option('-n, --sheet-rows ', 'Number of rows to process (0=all rows)') + .option('--codepage ', 'default to specified codepage when ambiguous') + .option('--sst', 'generate shared string table for XLS* formats') + .option('--compress', 'use compression when writing XLSX/M/B and ODS') + .option('--read', 'read but do not generate output') + .option('--book', 'for single-sheet formats, emit a file per worksheet') + .option('--all', 'parse everything; write as much as possible') + .option('--dev', 'development mode') + .option('--sparse', 'sparse mode') + .option('-q, --quiet', 'quiet mode'); program.on('--help', function() { - console.log(' Default output format is CSV'); - console.log(' Support email: dev@sheetjs.com'); - console.log(' Web Demo: http://oss.sheetjs.com/js-'+n+'/'); + console.log(' Default output format is CSV'); + console.log(' Support email: dev@sheetjs.com'); + console.log(' Web Demo: http://oss.sheetjs.com/js-'+n+'/'); }); /* flag, bookType, default ext */ var workbook_formats = [ - ['xlsx', 'xlsx', 'xlsx'], - ['xlsm', 'xlsm', 'xlsm'], - ['xlam', 'xlam', 'xlam'], - ['xlsb', 'xlsb', 'xlsb'], - ['xls', 'xls', 'xls'], - ['xla', 'xla', 'xla'], - ['biff5', 'biff5', 'xls'], - ['numbers', 'numbers', 'numbers'], - ['ods', 'ods', 'ods'], - ['fods', 'fods', 'fods'], - ['wk3', 'wk3', 'wk3'] + ['xlsx', 'xlsx', 'xlsx'], + ['xlsm', 'xlsm', 'xlsm'], + ['xlam', 'xlam', 'xlam'], + ['xlsb', 'xlsb', 'xlsb'], + ['xls', 'xls', 'xls'], + ['xla', 'xla', 'xla'], + ['biff5', 'biff5', 'xls'], + ['numbers', 'numbers', 'numbers'], + ['ods', 'ods', 'ods'], + ['fods', 'fods', 'fods'], + ['wk3', 'wk3', 'wk3'] ]; var wb_formats_2 = [ - ['xlml', 'xlml', 'xls'] + ['xlml', 'xlml', 'xls'] ]; program.parse(process.argv); var filename = '', sheetname = ''; if(program.args[0]) { - filename = program.args[0]; - if(program.args[1]) sheetname = program.args[1]; + filename = program.args[0]; + if(program.args[1]) sheetname = program.args[1]; } if(program.sheet) sheetname = program.sheet; if(program.file) filename = program.file; if(!filename) { - console.error(n + ": must specify a filename"); - process.exit(1); + console.error(n + ": must specify a filename"); + process.exit(1); } if(!fs.existsSync(filename)) { - console.error(n + ": " + filename + ": No such file or directory"); - process.exit(2); + console.error(n + ": " + filename + ": No such file or directory"); + process.exit(2); } var opts = {}, wb/*:?Workbook*/; @@ -119,16 +119,16 @@ if(program.sheetRows) opts.sheetRows = program.sheetRows; if(program.password) opts.password = program.password; var seen = false; function wb_fmt() { - seen = true; - opts.cellFormula = true; - opts.cellNF = true; - opts.xlfn = true; - if(program.output) sheetname = program.output; + seen = true; + opts.cellFormula = true; + opts.cellNF = true; + opts.xlfn = true; + if(program.output) sheetname = program.output; } function isfmt(m/*:string*/)/*:boolean*/ { - if(!program.output) return false; - var t = m.charAt(0) === "." ? m : "." + m; - return program.output.slice(-t.length) === t; + if(!program.output) return false; + var t = m.charAt(0) === "." ? m : "." + m; + return program.output.slice(-t.length) === t; } workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } }); wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } }); @@ -140,162 +140,162 @@ var wopts = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/); if(program.compress) wopts.compression = true; if(program.all) { - opts.cellFormula = true; - opts.bookVBA = true; - opts.cellNF = true; - opts.cellHTML = true; - opts.cellStyles = true; - opts.sheetStubs = true; - opts.cellDates = true; - wopts.cellFormula = true; - wopts.cellStyles = true; - wopts.sheetStubs = true; - wopts.bookVBA = true; + opts.cellFormula = true; + opts.bookVBA = true; + opts.cellNF = true; + opts.cellHTML = true; + opts.cellStyles = true; + opts.sheetStubs = true; + opts.cellDates = true; + wopts.cellFormula = true; + wopts.cellStyles = true; + wopts.sheetStubs = true; + wopts.bookVBA = true; } if(program.sparse) opts.dense = false; else opts.dense = true; if(program.codepage) opts.codepage = +program.codepage; if(program.dev) { - opts.WTF = true; - wb = X.readFile(filename, opts); + opts.WTF = true; + wb = X.readFile(filename, opts); } else try { - wb = X.readFile(filename, opts); + wb = X.readFile(filename, opts); } catch(e) { - var msg = (program.quiet) ? "" : n + ": error parsing "; - msg += filename + ": " + e; - console.error(msg); - process.exit(3); + var msg = (program.quiet) ? "" : n + ": error parsing "; + msg += filename + ": " + e; + console.error(msg); + process.exit(3); } if(program.read) process.exit(0); if(!wb) { console.error(n + ": error parsing " + filename + ": empty workbook"); process.exit(0); } /*:: if(!wb) throw new Error("unreachable"); */ if(program.listSheets) { - console.log((wb.SheetNames||[]).join("\n")); - process.exit(0); + console.log((wb.SheetNames||[]).join("\n")); + process.exit(0); } if(program.dump) { - console.log(JSON.stringify(wb)); - process.exit(0); + console.log(JSON.stringify(wb)); + process.exit(0); } if(program.props) { - if(wb) dump_props(wb); - process.exit(0); + if(wb) dump_props(wb); + process.exit(0); } /* full workbook formats */ workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { - wopts.bookType = m[1]; - if(wopts.bookType == "numbers") try { - var XLSX_ZAHL = require("xlsx/dist/xlsx.zahl"); - wopts.numbers = XLSX_ZAHL; - } catch(e) {} - if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); - process.exit(0); + wopts.bookType = m[1]; + if(wopts.bookType == "numbers") try { + var XLSX_ZAHL = require("xlsx/dist/xlsx.zahl"); + wopts.numbers = XLSX_ZAHL; + } catch(e) {} + if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); + process.exit(0); } }); wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { - wopts.bookType = m[1]; - if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); - process.exit(0); + wopts.bookType = m[1]; + if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts); + process.exit(0); } }); var target_sheet = sheetname || ''; if(target_sheet === '') { - if(+program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[+program.sheetIndex]; - else target_sheet = (wb.SheetNames||[""])[0]; + if(+program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[+program.sheetIndex]; + else target_sheet = (wb.SheetNames||[""])[0]; } var ws; try { - ws = wb.Sheets[target_sheet]; - if(!ws) { - console.error("Sheet " + target_sheet + " cannot be found"); - process.exit(3); - } + ws = wb.Sheets[target_sheet]; + if(!ws) { + console.error("Sheet " + target_sheet + " cannot be found"); + process.exit(3); + } } catch(e) { - console.error(n + ": error parsing "+filename+" "+target_sheet+": " + e); - process.exit(4); + console.error(n + ": error parsing "+filename+" "+target_sheet+": " + e); + process.exit(4); } if(!program.quiet && !program.book) console.error(target_sheet); /* single worksheet file formats */ [ - ['biff2', '.xls'], - ['biff3', '.xls'], - ['biff4', '.xls'], - ['sylk', '.slk'], - ['html', '.html'], - ['prn', '.prn'], - ['eth', '.eth'], - ['rtf', '.rtf'], - ['txt', '.txt'], - ['dbf', '.dbf'], - ['wk1', '.wk1'], - ['dif', '.dif'] + ['biff2', '.xls'], + ['biff3', '.xls'], + ['biff4', '.xls'], + ['sylk', '.slk'], + ['html', '.html'], + ['prn', '.prn'], + ['eth', '.eth'], + ['rtf', '.rtf'], + ['txt', '.txt'], + ['dbf', '.dbf'], + ['wk1', '.wk1'], + ['dif', '.dif'] ].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) { - wopts.bookType = m[0]; - if(program.book) { - /*:: if(wb == null) throw new Error("Unreachable"); */ - wb.SheetNames.forEach(function(n, i) { - wopts.sheet = n; - X.writeFile(wb, (program.output || sheetname || filename || "") + m[1] + "." + i, wopts); - }); - } else X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts); - process.exit(0); + wopts.bookType = m[0]; + if(program.book) { + /*:: if(wb == null) throw new Error("Unreachable"); */ + wb.SheetNames.forEach(function(n, i) { + wopts.sheet = n; + X.writeFile(wb, (program.output || sheetname || filename || "") + m[1] + "." + i, wopts); + }); + } else X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts); + process.exit(0); } }); function outit(o, fn) { if(fn) fs.writeFileSync(fn, o); else console.log(o); } function doit(cb) { - /*:: if(!wb) throw new Error("unreachable"); */ - if(program.book) wb.SheetNames.forEach(function(n, i) { - /*:: if(!wb) throw new Error("unreachable"); */ - outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i); - }); - else outit(cb(ws), program.output); + /*:: if(!wb) throw new Error("unreachable"); */ + if(program.book) wb.SheetNames.forEach(function(n, i) { + /*:: if(!wb) throw new Error("unreachable"); */ + outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i); + }); + else outit(cb(ws), program.output); } var jso = {}; switch(true) { - case program.formulae: - doit(function(ws) { return X.utils.sheet_to_formulae(ws).join("\n"); }); - break; + case program.formulae: + doit(function(ws) { return X.utils.sheet_to_formulae(ws).join("\n"); }); + break; - case program.arrays: jso.header = 1; - /* falls through */ - case program.rawJs: jso.raw = true; - /* falls through */ - case program.json: - doit(function(ws) { return JSON.stringify(X.utils.sheet_to_json(ws,jso)); }); - break; + case program.arrays: jso.header = 1; + /* falls through */ + case program.rawJs: jso.raw = true; + /* falls through */ + case program.json: + doit(function(ws) { return JSON.stringify(X.utils.sheet_to_json(ws,jso)); }); + break; - default: - if(!program.book) { - var stream = X.stream.to_csv(ws, {FS:program.fieldSep||",", RS:program.rowSep||"\n"}); - if(program.output) stream.pipe(fs.createWriteStream(program.output)); - else stream.pipe(process.stdout); - } else doit(function(ws) { return X.utils.sheet_to_csv(ws,{FS:program.fieldSep, RS:program.rowSep}); }); - break; + default: + if(!program.book) { + var stream = X.stream.to_csv(ws, {FS:program.fieldSep||",", RS:program.rowSep||"\n"}); + if(program.output) stream.pipe(fs.createWriteStream(program.output)); + else stream.pipe(process.stdout); + } else doit(function(ws) { return X.utils.sheet_to_csv(ws,{FS:program.fieldSep, RS:program.rowSep}); }); + break; } function dump_props(wb/*:Workbook*/) { - var propaoa = []; - if(Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops)); - else { - var Keys/*:: :Array = []*/, pi; - if(wb.Props) { - Keys = Object.keys(wb.Props); - for(pi = 0; pi < Keys.length; ++pi) { - if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]); - } - } - if(wb.Custprops) { - Keys = Object.keys(wb.Custprops); - for(pi = 0; pi < Keys.length; ++pi) { - if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]); - } - } - } - console.log(X.utils.sheet_to_csv(X.utils.aoa_to_sheet(propaoa))); + var propaoa = []; + if(Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops)); + else { + var Keys/*:: :Array = []*/, pi; + if(wb.Props) { + Keys = Object.keys(wb.Props); + for(pi = 0; pi < Keys.length; ++pi) { + if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]); + } + } + if(wb.Custprops) { + Keys = Object.keys(wb.Custprops); + for(pi = 0; pi < Keys.length; ++pi) { + if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]); + } + } + } + console.log(X.utils.sheet_to_csv(X.utils.aoa_to_sheet(propaoa))); } diff --git a/docz/static/electron/index.html b/docz/static/electron/index.html index aab9086..d59ee74 100644 --- a/docz/static/electron/index.html +++ b/docz/static/electron/index.html @@ -8,13 +8,13 @@ SheetJS Electron Demo diff --git a/docz/static/electron/index.js b/docz/static/electron/index.js index 28696e0..35327a2 100644 --- a/docz/static/electron/index.js +++ b/docz/static/electron/index.js @@ -51,7 +51,7 @@ document.getElementById('readBtn').addEventListener('click', handleReadBtn, fals /* read file with Web APIs */ async function readFile(files) { const f = files[0]; - const data = await f.arrayBuffer(); + const data = await f.arrayBuffer(); process_wb(XLSX.read(data)); } diff --git a/docz/static/electron/main.js b/docz/static/electron/main.js index 7090a39..36cff16 100644 --- a/docz/static/electron/main.js +++ b/docz/static/electron/main.js @@ -7,20 +7,20 @@ require('@electron/remote/main').initialize(); // required for Electron 14+ var win = null; function createWindow() { - if (win) return; - win = new electron.BrowserWindow({ - width: 800, height: 600, - webPreferences: { - worldSafeExecuteJavaScript: true, // required for Electron 12+ - contextIsolation: false, // required for Electron 12+ - nodeIntegration: true, - enableRemoteModule: true - } - }); - win.loadURL("file://" + __dirname + "/index.html"); - require('@electron/remote/main').enable(win.webContents); // required for Electron 14+ - win.webContents.openDevTools(); - win.on('closed', function () { win = null; }); + if (win) return; + win = new electron.BrowserWindow({ + width: 800, height: 600, + webPreferences: { + worldSafeExecuteJavaScript: true, // required for Electron 12+ + contextIsolation: false, // required for Electron 12+ + nodeIntegration: true, + enableRemoteModule: true + } + }); + win.loadURL("file://" + __dirname + "/index.html"); + require('@electron/remote/main').enable(win.webContents); // required for Electron 14+ + win.webContents.openDevTools(); + win.on('closed', function () { win = null; }); } if (app.setAboutPanelOptions) app.setAboutPanelOptions({ applicationName: 'sheetjs-electron', applicationVersion: "XLSX " + XLSX.version, copyright: "(C) 2017-present SheetJS LLC" }); app.on('open-file', function () { console.log(arguments); }); diff --git a/docz/static/rhino/SheetJSRhino.zip b/docz/static/rhino/SheetJSRhino.zip new file mode 100644 index 0000000..920da3d Binary files /dev/null and b/docz/static/rhino/SheetJSRhino.zip differ diff --git a/docz/static/swift/SheetJSCore.swift b/docz/static/swift/SheetJSCore.swift new file mode 100755 index 0000000..0fc14f5 --- /dev/null +++ b/docz/static/swift/SheetJSCore.swift @@ -0,0 +1,96 @@ +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +import JavaScriptCore; + +enum SJSError: Error { + case badJSContext; + case badJSWorkbook; + case badJSWorksheet; +}; + +class SJSWorksheet { + var context: JSContext!; + var wb: JSValue; var ws: JSValue; + var idx: Int32; + + func toCSV() throws -> String { + let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + let utils: JSValue! = XLSX.objectForKeyedSubscript("utils"); + let sheet_to_csv: JSValue! = utils.objectForKeyedSubscript("sheet_to_csv"); + return sheet_to_csv.call(withArguments: [ws]).toString(); + } + + init(ctx: JSContext, workbook: JSValue, worksheet: JSValue, idx: Int32) throws { + self.context = ctx; self.wb = workbook; self.ws = worksheet; self.idx = idx; + } +} + +class SJSWorkbook { + var context: JSContext!; + var wb: JSValue; var SheetNames: JSValue; var Sheets: JSValue; + + func getSheetAtIndex(idx: Int32) throws -> SJSWorksheet { + let SheetName: String = SheetNames.atIndex(Int(idx)).toString(); + let ws: JSValue! = Sheets.objectForKeyedSubscript(SheetName); + return try SJSWorksheet(ctx: context, workbook: wb, worksheet: ws, idx: idx); + } + + func writeBStr(bookType: String = "xlsx") throws -> String { + let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + context.evaluateScript(String(format: "var writeopts = {type:'binary', bookType:'%@'}", bookType)); + let writeopts: JSValue = context.objectForKeyedSubscript("writeopts"); + let writefunc: JSValue = XLSX.objectForKeyedSubscript("write"); + return writefunc.call(withArguments: [wb, writeopts]).toString(); + } + + init(ctx: JSContext, wb: JSValue) throws { + self.context = ctx; + self.wb = wb; + self.SheetNames = wb.objectForKeyedSubscript("SheetNames"); + self.Sheets = wb.objectForKeyedSubscript("Sheets"); + } +} + +class SheetJSCore { + var context: JSContext!; + var XLSX: JSValue!; + + func init_context() throws -> JSContext { + var context: JSContext! + do { + context = JSContext(); + context.exceptionHandler = { _, X in if let e = X { print(e.toString()!); }; }; + context.evaluateScript("var global = (function(){ return this; }).call(null);"); + context.evaluateScript("if(typeof wbs == 'undefined') wbs = [];"); + let src = try String(contentsOfFile: "xlsx.full.min.js"); + context.evaluateScript(src); + if context != nil { return context!; } + } catch { print(error.localizedDescription); } + throw SJSError.badJSContext; + } + + func version() throws -> String { + if let version = XLSX.objectForKeyedSubscript("version") { return version.toString(); } + throw SJSError.badJSContext; + } + + func readFile(file: String) throws -> SJSWorkbook { + let data: String! = try String(contentsOfFile: file, encoding: String.Encoding.isoLatin1); + return try readBStr(data: data); + } + + func readBStr(data: String) throws -> SJSWorkbook { + context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)); + context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});"); + let wb: JSValue! = context.objectForKeyedSubscript("wb"); + if wb == nil { throw SJSError.badJSWorkbook; } + return try SJSWorkbook(ctx: context, wb: wb); + } + + init() throws { + do { + self.context = try init_context(); + self.XLSX = self.context.objectForKeyedSubscript("XLSX"); + if self.XLSX == nil { throw SJSError.badJSContext; } + } catch { print(error.localizedDescription); } + } +} diff --git a/docz/static/swift/main.swift b/docz/static/swift/main.swift new file mode 100755 index 0000000..28adf27 --- /dev/null +++ b/docz/static/swift/main.swift @@ -0,0 +1,17 @@ +/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +let sheetjs = try SheetJSCore(); + +/* Print the SheetJS library version */ +try print(sheetjs.version()); + +/* Read file */ +let wb: SJSWorkbook = try sheetjs.readFile(file: CommandLine.arguments[1]); + +/* Convert the first worksheet to CSV and print */ +let ws: SJSWorksheet = try wb.getSheetAtIndex(idx: 0); +let csv: String = try ws.toCSV(); +print(csv); + +/* write an XLSX file to SheetJSwift.xlsx */ +let wbout: String = try wb.writeBStr(bookType: "xlsx"); +try wbout.write(toFile: "SheetJSwift.xlsx", atomically: false, encoding: String.Encoding.isoLatin1); diff --git a/docz/static/systemjs/main.js b/docz/static/systemjs/main.js index 8bfe87a..a4d0a79 100644 --- a/docz/static/systemjs/main.js +++ b/docz/static/systemjs/main.js @@ -6,124 +6,124 @@ var XLSX = require('xlsx'); var global_wb; var process_wb = (function() { - var OUT = document.getElementById('out'); - var HTMLOUT = document.getElementById('htmlout'); + var OUT = document.getElementById('out'); + var HTMLOUT = document.getElementById('htmlout'); - var get_format = (function() { - var radios = document.getElementsByName( "format" ); - return function() { - for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value; - }; - })(); + var get_format = (function() { + var radios = document.getElementsByName( "format" ); + return function() { + for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value; + }; + })(); - var to_json = function to_json(workbook) { - var result = {}; - workbook.SheetNames.forEach(function(sheetName) { - var roa = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); - if(roa.length) result[sheetName] = roa; - }); - return JSON.stringify(result, 2, 2); - }; + var to_json = function to_json(workbook) { + var result = {}; + workbook.SheetNames.forEach(function(sheetName) { + var roa = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); + if(roa.length) result[sheetName] = roa; + }); + return JSON.stringify(result, 2, 2); + }; - var to_csv = function to_csv(workbook) { - var result = []; - workbook.SheetNames.forEach(function(sheetName) { - var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); - if(csv.length){ - result.push("SHEET: " + sheetName); - result.push(""); - result.push(csv); - } - }); - return result.join("\n"); - }; + var to_csv = function to_csv(workbook) { + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); + if(csv.length){ + result.push("SHEET: " + sheetName); + result.push(""); + result.push(csv); + } + }); + return result.join("\n"); + }; - var to_fmla = function to_fmla(workbook) { - var result = []; - workbook.SheetNames.forEach(function(sheetName) { - var formulae = XLSX.utils.get_formulae(workbook.Sheets[sheetName]); - if(formulae.length){ - result.push("SHEET: " + sheetName); - result.push(""); - result.push(formulae.join("\n")); - } - }); - return result.join("\n"); - }; + var to_fmla = function to_fmla(workbook) { + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var formulae = XLSX.utils.get_formulae(workbook.Sheets[sheetName]); + if(formulae.length){ + result.push("SHEET: " + sheetName); + result.push(""); + result.push(formulae.join("\n")); + } + }); + return result.join("\n"); + }; - var to_html = function to_html(workbook) { - HTMLOUT.innerHTML = ""; - workbook.SheetNames.forEach(function(sheetName) { - var htmlstr = XLSX.write(workbook, {sheet:sheetName, type:'string', bookType:'html'}); - HTMLOUT.innerHTML += htmlstr; - }); - return ""; - }; + var to_html = function to_html(workbook) { + HTMLOUT.innerHTML = ""; + workbook.SheetNames.forEach(function(sheetName) { + var htmlstr = XLSX.write(workbook, {sheet:sheetName, type:'string', bookType:'html'}); + HTMLOUT.innerHTML += htmlstr; + }); + return ""; + }; - return function process_wb(wb) { - global_wb = wb; - var output = ""; - switch(get_format()) { - case "form": output = to_fmla(wb); break; - case "html": output = to_html(wb); break; - case "json": output = to_json(wb); break; - default: output = to_csv(wb); - } - if(OUT.innerText === undefined) OUT.textContent = output; - else OUT.innerText = output; - if(typeof console !== 'undefined') console.log("output", new Date()); - }; + return function process_wb(wb) { + global_wb = wb; + var output = ""; + switch(get_format()) { + case "form": output = to_fmla(wb); break; + case "html": output = to_html(wb); break; + case "json": output = to_json(wb); break; + default: output = to_csv(wb); + } + if(OUT.innerText === undefined) OUT.textContent = output; + else OUT.innerText = output; + if(typeof console !== 'undefined') console.log("output", new Date()); + }; })(); var setfmt = window.setfmt = function setfmt() { if(global_wb) process_wb(global_wb); }; var b64it = window.b64it = (function() { - var tarea = document.getElementById('b64data'); - return function b64it() { - if(typeof console !== 'undefined') console.log("onload", new Date()); - var wb = XLSX.read(tarea.value, {type:'base64', WTF:false}); - process_wb(wb); - }; + var tarea = document.getElementById('b64data'); + return function b64it() { + if(typeof console !== 'undefined') console.log("onload", new Date()); + var wb = XLSX.read(tarea.value, {type:'base64', WTF:false}); + process_wb(wb); + }; })(); var do_file = (function() { - return function do_file(files) { - var f = files[0]; - var reader = new FileReader(); - reader.onload = function(e) { - if(typeof console !== 'undefined') console.log("onload", new Date()); - var data = e.target.result; - data = new Uint8Array(data); - process_wb(XLSX.read(data, {type: 'array'})); - }; - reader.readAsArrayBuffer(f); - }; + return function do_file(files) { + var f = files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + if(typeof console !== 'undefined') console.log("onload", new Date()); + var data = e.target.result; + data = new Uint8Array(data); + process_wb(XLSX.read(data, {type: 'array'})); + }; + reader.readAsArrayBuffer(f); + }; })(); (function() { - var drop = document.getElementById('drop'); - if(!drop.addEventListener) return; + var drop = document.getElementById('drop'); + if(!drop.addEventListener) return; - function handleDrop(e) { - e.stopPropagation(); - e.preventDefault(); - do_file(e.dataTransfer.files); - } + function handleDrop(e) { + e.stopPropagation(); + e.preventDefault(); + do_file(e.dataTransfer.files); + } - function handleDragover(e) { - e.stopPropagation(); - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - } + function handleDragover(e) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + } - drop.addEventListener('dragenter', handleDragover, false); - drop.addEventListener('dragover', handleDragover, false); - drop.addEventListener('drop', handleDrop, false); + drop.addEventListener('dragenter', handleDragover, false); + drop.addEventListener('dragover', handleDragover, false); + drop.addEventListener('drop', handleDrop, false); })(); (function() { - var xlf = document.getElementById('xlf'); - if(!xlf.addEventListener) return; - function handleFile(e) { do_file(e.target.files); } - xlf.addEventListener('change', handleFile, false); + var xlf = document.getElementById('xlf'); + if(!xlf.addEventListener) return; + function handleFile(e) { do_file(e.target.files); } + xlf.addEventListener('change', handleFile, false); })(); diff --git a/docz/static/systemjs/systemjs.html b/docz/static/systemjs/systemjs.html index 18a4288..7219052 100644 --- a/docz/static/systemjs/systemjs.html +++ b/docz/static/systemjs/systemjs.html @@ -7,16 +7,16 @@ SheetJS Live Demo @@ -46,32 +46,32 @@ Output Format: