rhino
This commit is contained in:
parent
39b171c011
commit
8517e019e0
196
docz/docs/03-demos/31-engines/03_rhino.md
Normal file
196
docz/docs/03-demos/31-engines/03_rhino.md
Normal file
@ -0,0 +1,196 @@
|
||||
---
|
||||
title: Java + Rhino
|
||||
pagination_prev: demos/cli
|
||||
pagination_next: demos/clipboard
|
||||
---
|
||||
|
||||
Rhino is an ES3+ engine in Java.
|
||||
|
||||
The [Standalone scripts](/docs/getting-started/installation/standalone) can be
|
||||
parsed and evaluated in a Rhino context.
|
||||
|
||||
This demo wraps workbooks and sheets into separate Java classes. The final
|
||||
result is a JAR.
|
||||
|
||||
:::caution
|
||||
|
||||
Rhino does not support Uint8Array, so certain formats like NUMBERS cannot be
|
||||
parsed or written from Rhino JS code!
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
:::note
|
||||
|
||||
Due to code generation errors, optimization must be turned off:
|
||||
|
||||
```java
|
||||
Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Binary strings can be passed back and forth.
|
||||
|
||||
_Initialize Rhino_
|
||||
|
||||
Rhino does not provide a `global` variable. It can be created:
|
||||
|
||||
```java
|
||||
Context cx = Context.enter();
|
||||
Scriptable scope = cx.initStandardObjects();
|
||||
|
||||
/* Disable optimization */
|
||||
cx.setOptimizationLevel(-1);
|
||||
|
||||
/* Initialize `global` variable */
|
||||
// highlight-start
|
||||
String s = "var global = (function(){ return this; }).call(null);";
|
||||
cx.evaluateString(scope, s, "<cmd>", 1, null);
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
_Load SheetJS Scripts_
|
||||
|
||||
The main library can be loaded by reading the scripts from the Java Archive and
|
||||
evaluating in the Rhino context:
|
||||
|
||||
```java
|
||||
/* pull source from JAR */
|
||||
String s = new Scanner(
|
||||
SheetJS.class.getResourceAsStream("/xlsx.full.min.js")
|
||||
).useDelimiter("\\Z").next();
|
||||
/* evaluate */
|
||||
cx.evaluateString(scope, s, "<cmd>", 1, null);
|
||||
```
|
||||
|
||||
To confirm the library is loaded, `XLSX.version` can be inspected:
|
||||
|
||||
```swift
|
||||
/* get handle to XLSX */
|
||||
Object XLSX = scope.get("XLSX", scope);
|
||||
if(XLSX == Scriptable.NOT_FOUND) throw new Exception("XLSX not found");
|
||||
|
||||
/* get the version string */
|
||||
String version = ((NativeObject)XLSX).get("version", scope).toString();
|
||||
System.out.println("SheetJS version " + version);
|
||||
```
|
||||
|
||||
### Reading Files
|
||||
|
||||
A binary string can be generated from a `byte` array:
|
||||
|
||||
```java
|
||||
static String read_file(String file) throws IOException {
|
||||
/* read file -> array of bytes */
|
||||
byte[] b = Files.readAllBytes(Paths.get(file));
|
||||
|
||||
/* construct binary string */
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i = 0; i < b.length; ++i) sb.append(Character.toString((char)(b[i] < 0 ? b[i] + 256 : b[i])));
|
||||
return sb.toString();
|
||||
}
|
||||
```
|
||||
|
||||
This string can be loaded into the JS engine and processed:
|
||||
|
||||
```java
|
||||
/* options argument */
|
||||
String os = "q = {'type':'binary', 'WTF':1};";
|
||||
NativeObject o = (NativeObject)cx.evaluateString(scope, os, "<cmd>", 2, null);
|
||||
|
||||
/* set up function arguments */
|
||||
String data = read_file(path_to_file);
|
||||
Object args[] = {data, o};
|
||||
|
||||
/* call read -> wb workbook */
|
||||
NativeObject nXLSX = (NativeObject)XLSX;
|
||||
Function readfunc = (Function)XLSX.get("read", scope);
|
||||
NativeObject wb = (NativeObject)readfunc.call(cx, scope, nXLSX, args);
|
||||
```
|
||||
|
||||
`wb` will be a reference to the JS workbook object.
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note
|
||||
|
||||
This demo was tested on 2023 February 14 using Rhino 1.7.14.
|
||||
|
||||
:::
|
||||
|
||||
0) Ensure Java is installed. Create a folder for the project, download the
|
||||
[JAR](https://github.com/mozilla/rhino/releases/download/Rhino1_7_14_Release/rhino-1.7.14.jar)
|
||||
and rename to `rhino.jar`:
|
||||
|
||||
```bash
|
||||
mkdir sheetjs-java
|
||||
cd sheetjs-java
|
||||
curl -L -o rhino.jar https://github.com/mozilla/rhino/releases/download/Rhino1_7_14_Release/rhino-1.7.14.jar
|
||||
```
|
||||
|
||||
1) Download the standalone script and the test file:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
||||
</ul>
|
||||
|
||||
```bash
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
|
||||
curl -LO https://sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
2) Download [`SheetJSRhino.zip`](pathname:///rhino/SheetJSRhino.zip) and unzip
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/rhino/SheetJSRhino.zip
|
||||
unzip SheetJSRhino.zip
|
||||
```
|
||||
|
||||
3) Save the following code to `SheetJSRhino.java`:
|
||||
|
||||
```java title="SheetJSRhino.java"
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://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(); }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4) Assemble `SheetJS.jar` from the demo code:
|
||||
|
||||
```bash
|
||||
javac -cp .:rhino.jar SheetJSRhino.java
|
||||
jar -cf SheetJS.jar SheetJSRhino.class com/sheetjs/*.class xlsx.full.min.js
|
||||
```
|
||||
|
||||
5) Test the program:
|
||||
|
||||
```bash
|
||||
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino pres.xlsx
|
||||
```
|
||||
|
||||
If successful, a CSV will be printed to console.
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Ruby Bindings
|
||||
title: Ruby + Bindings
|
||||
pagination_prev: demos/cli
|
||||
pagination_next: demos/clipboard
|
||||
---
|
||||
|
@ -115,66 +115,10 @@ cpan install JE
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.extendscript.js
|
||||
```
|
||||
|
||||
3) Save the following to `SheetJE.pl`:
|
||||
3) Download the demo [`SheetJE.pl`](pathname:///perl/SheetJE.pl):
|
||||
|
||||
```perl title="SheetJE.pl"
|
||||
use JE;
|
||||
use File::Slurp;
|
||||
use MIME::Base64 qw( encode_base64 );
|
||||
|
||||
## Initialize
|
||||
say STDERR "Initializing Engine";
|
||||
my $je = new JE;
|
||||
$je->eval("var global = (function(){ return this; }).call(null);");
|
||||
$je->eval(<<'EOF');
|
||||
Number.prototype.charCodeAt = function(n) { return this + 48; };
|
||||
var string = ""; for(var i = 0; i < 256; ++i) string += String.fromCharCode(i);
|
||||
String.prototype.charCodeAt = function(n) {
|
||||
var result = string.indexOf(this.charAt(n));
|
||||
if(result == -1) throw this.charAt(n);
|
||||
return result;
|
||||
};
|
||||
String.prototype.old_match = String.prototype.match;
|
||||
String.prototype.match = function(p) {
|
||||
var result = this.old_match(p);
|
||||
return (Array.isArray(result) && result.length == 0) ? null : result;
|
||||
};
|
||||
EOF
|
||||
|
||||
## Load SheetJS source
|
||||
say STDERR "Loading SheetJS Library";
|
||||
my $src = read_file('xlsx.extendscript.js', { binmode => ':raw' });
|
||||
$src =~ s/^\xEF\xBB\xBF//;
|
||||
my $XLSX = $je->eval($src);
|
||||
|
||||
## Set up conversion method
|
||||
$je->eval(<<'EOF');
|
||||
function sheetjsparse(data) { try {
|
||||
return XLSX.read(String(data), {type: "base64", WTF:1});
|
||||
} catch(e) { return String(e); } }
|
||||
function sheetjscsv(wb) { try {
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
return XLSX.utils.sheet_to_csv(ws);
|
||||
} catch(e) { return String(e); } }
|
||||
function sheetjswrite(wb) { try {
|
||||
return XLSX.write(wb, { WTF:1, bookType: "fods", type: "string" });
|
||||
} catch(e) { return String(e); } }
|
||||
EOF
|
||||
|
||||
## Read file
|
||||
say STDERR "Parsing " . $ARGV[0];
|
||||
my $raw_data = encode_base64(read_file($ARGV[0], { binmode => ':raw' }), "");
|
||||
$workbook = $je->method(sheetjsparse => $raw_data);
|
||||
|
||||
## Convert to CSV
|
||||
say STDERR "Converting to CSV";
|
||||
my $csv_data = $je->method(sheetjscsv => $workbook);
|
||||
print $csv_data;
|
||||
|
||||
## Write to SheetJE.fods
|
||||
say STDERR "Writing to SheetJE.fods";
|
||||
my $fods = $je->method(sheetjswrite => $workbook);
|
||||
write_file("SheetJE.fods", $fods);
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/perl/SheetJE.pl
|
||||
```
|
||||
|
||||
4) Download a test file and run:
|
||||
|
@ -301,72 +301,9 @@ 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.
|
||||
Rhino is an ES3+ engine in Java.
|
||||
|
||||
Due to code generation errors, optimization must be turned off:
|
||||
|
||||
```java
|
||||
Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
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 -- https://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 <https://sheetjs.com/pres.xlsx> and test:
|
||||
|
||||
```bash
|
||||
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino pres.xlsx
|
||||
```
|
||||
|
||||
</details>
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/rhino).
|
||||
|
||||
## Legacy Engines
|
||||
|
||||
|
@ -129,6 +129,25 @@ async function fetch_workbook_and_error_on_404(url) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Cloudflare Worker "Error: Script startup exceeded CPU time limit."
|
||||
|
||||
This may show up in projects with many dependencies. The official workaround is
|
||||
dynamic `import`. For example:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
||||
// highlight-next-line
|
||||
const XLSX = await import("xlsx"); // dynamic import
|
||||
const wb = XLSX.read("abc\n123", {type: "string"});
|
||||
const buf = XLSX.write(wb, {type: "buffer", bookType: "xlsb"});
|
||||
const response = new Response(buf);
|
||||
response.headers.set("Content-Disposition", 'attachment; filename="cf.xlsb"');
|
||||
return response;
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### SCRIPT5022: DataCloneError
|
||||
|
||||
IE10 does not properly support `Transferable`.
|
||||
|
59
docz/static/perl/SheetJE.pl
Normal file
59
docz/static/perl/SheetJE.pl
Normal file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env perl
|
||||
# SheetJE.pl (c) SheetJS LLC -- https://sheetjs.com
|
||||
use JE;
|
||||
use File::Slurp;
|
||||
use MIME::Base64 qw( encode_base64 );
|
||||
|
||||
## Initialize
|
||||
say STDERR "Initializing Engine";
|
||||
my $je = new JE;
|
||||
$je->eval("var global = (function(){ return this; }).call(null);");
|
||||
$je->eval(<<'EOF');
|
||||
Number.prototype.charCodeAt = function(n) { return this + 48; };
|
||||
var string = ""; for(var i = 0; i < 256; ++i) string += String.fromCharCode(i);
|
||||
String.prototype.charCodeAt = function(n) {
|
||||
var result = string.indexOf(this.charAt(n));
|
||||
if(result == -1) throw this.charAt(n);
|
||||
return result;
|
||||
};
|
||||
String.prototype.old_match = String.prototype.match;
|
||||
String.prototype.match = function(p) {
|
||||
var result = this.old_match(p);
|
||||
return (Array.isArray(result) && result.length == 0) ? null : result;
|
||||
};
|
||||
EOF
|
||||
|
||||
## Load SheetJS source
|
||||
say STDERR "Loading SheetJS Library";
|
||||
my $src = read_file('xlsx.extendscript.js', { binmode => ':raw' });
|
||||
$src =~ s/^\xEF\xBB\xBF//;
|
||||
my $XLSX = $je->eval($src);
|
||||
|
||||
## Set up conversion method
|
||||
$je->eval(<<'EOF');
|
||||
function sheetjsparse(data) { try {
|
||||
return XLSX.read(String(data), {type: "base64", WTF:1});
|
||||
} catch(e) { return String(e); } }
|
||||
function sheetjscsv(wb) { try {
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
return XLSX.utils.sheet_to_csv(ws);
|
||||
} catch(e) { return String(e); } }
|
||||
function sheetjswrite(wb) { try {
|
||||
return XLSX.write(wb, { WTF:1, bookType: "fods", type: "string" });
|
||||
} catch(e) { return String(e); } }
|
||||
EOF
|
||||
|
||||
## Read file
|
||||
say STDERR "Parsing " . $ARGV[0];
|
||||
my $raw_data = encode_base64(read_file($ARGV[0], { binmode => ':raw' }), "");
|
||||
$workbook = $je->method(sheetjsparse => $raw_data);
|
||||
|
||||
## Convert to CSV
|
||||
say STDERR "Converting to CSV";
|
||||
my $csv_data = $je->method(sheetjscsv => $workbook);
|
||||
print $csv_data;
|
||||
|
||||
## Write to SheetJE.fods
|
||||
say STDERR "Writing to SheetJE.fods";
|
||||
my $fods = $je->method(sheetjswrite => $workbook);
|
||||
write_file("SheetJE.fods", $fods);
|
Loading…
Reference in New Issue
Block a user