forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			197 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			197 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | --- | ||
|  | 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. |