forked from sheetjs/sheetjs
stox skip blank worksheets [ci skip]
This commit is contained in:
parent
d55b7a3063
commit
c02eb14255
@ -26,7 +26,7 @@ can be installed with Bash on Windows or with `cygwin`.
|
||||
- [`IndexedDB`](https://docs.sheetjs.com/docs/getting-started/demos/database#indexeddb)
|
||||
|
||||
**Frameworks**
|
||||
- [`Angular.JS`](angular/)
|
||||
- [`Angular.JS`](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
|
||||
- [`Angular 2+ and Ionic`](angular2/)
|
||||
- [`Knockout`](https://docs.sheetjs.com/docs/getting-started/demos/legacy#knockoutjs)
|
||||
- [`Meteor`](meteor/)
|
||||
@ -34,17 +34,19 @@ can be installed with Bash on Windows or with `cygwin`.
|
||||
- [`VueJS, WeeX and NuxtJS`](vue/)
|
||||
|
||||
**Front-End UI Components**
|
||||
- [`canvas-datagrid`](datagrid/)
|
||||
- [`canvas-datagrid`](https://docs.sheetjs.com/docs/getting-started/demos/grid#canvas-datagrid)
|
||||
- [`x-spreadsheet`](xspreadsheet/)
|
||||
- [`react-data-grid`](react/modify/)
|
||||
- [`vue3-table-light`](vue/modify/)
|
||||
- [`angular-ui-grid`](https://docs.sheetjs.com/docs/getting-started/demos/grid#angular-ui-grid)
|
||||
|
||||
**Platforms and Integrations**
|
||||
- [`Command-Line Tools`](https://docs.sheetjs.com/docs/getting-started/demos/cli)
|
||||
- [`NodeJS Server-Side Processing`](server/)
|
||||
- [`Deno`](deno/)
|
||||
- [`Electron`](electron/)
|
||||
- [`NW.js`](nwjs/)
|
||||
- [`Chrome / Chromium Extension`](chrome/)
|
||||
- [`NW.js`](https://docs.sheetjs.com/docs/getting-started/demos/desktop#nwjs)
|
||||
- [`Chrome / Chromium Extension`](https://docs.sheetjs.com/docs/getting-started/demos/chromium)
|
||||
- [`Google Sheets API`](https://docs.sheetjs.com/docs/getting-started/demos/gsheet)
|
||||
- [`ExtendScript for Adobe Apps`](https://docs.sheetjs.com/docs/getting-started/demos/extendscript)
|
||||
- [`NetSuite SuiteScript`](https://docs.sheetjs.com/docs/getting-started/demos/netsuite)
|
||||
@ -53,10 +55,9 @@ can be installed with Bash on Windows or with `cygwin`.
|
||||
- [`Headless Automation`](https://docs.sheetjs.com/docs/getting-started/demos/headless)
|
||||
- [`Swift JSC and Other JavaScript Engines`](altjs/)
|
||||
- [`"serverless" functions`](function/)
|
||||
- [`databases and key/value stores`](database/)
|
||||
- [`Databases and Structured Data Stores`](https://docs.sheetjs.com/docs/getting-started/demos/database)
|
||||
- [`NoSQL, K/V, and Unstructured Data Stores`](https://docs.sheetjs.com/docs/getting-started/demos/nosql)
|
||||
- [`internet explorer`](oldie/)
|
||||
- [`Legacy Internet Explorer`](oldie/)
|
||||
|
||||
**Bundlers and Tooling**
|
||||
- [`browserify`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#browserify)
|
||||
@ -68,7 +69,6 @@ can be installed with Bash on Windows or with `cygwin`.
|
||||
- [`snowpack`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#snowpack)
|
||||
- [`swc`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#swc)
|
||||
- [`systemjs`](systemjs/)
|
||||
- [`typescript`](typescript/)
|
||||
- [`vite`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#vite)
|
||||
- [`webpack 2.x`](webpack/)
|
||||
- [`wmr`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#wmr)
|
||||
|
@ -1,148 +1,10 @@
|
||||
# AngularJS
|
||||
|
||||
The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped
|
||||
into web pages with script tags:
|
||||
|
||||
```html
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
```
|
||||
|
||||
Strictly speaking, there should be no need for an Angular demo! You can proceed
|
||||
as you would with any other browser-friendly library.
|
||||
|
||||
This demo uses AngularJS 1.5.0.
|
||||
|
||||
|
||||
## Array of Objects
|
||||
|
||||
A common data table is often stored as an array of objects:
|
||||
|
||||
```js
|
||||
$scope.data = [
|
||||
{ Name: "Bill Clinton", Index: 42 },
|
||||
{ Name: "GeorgeW Bush", Index: 43 },
|
||||
{ Name: "Barack Obama", Index: 44 },
|
||||
{ Name: "Donald Trump", Index: 45 }
|
||||
];
|
||||
```
|
||||
|
||||
This neatly maps to a table with `ng-repeat`:
|
||||
|
||||
```html
|
||||
<table id="sjs-table">
|
||||
<tr><th>Name</th><th>Index</th></tr>
|
||||
<tr ng-repeat="row in data">
|
||||
<td>{{row.Name}}</td>
|
||||
<td>{{row.Index}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
The `$http` service can request binary data using the `"arraybuffer"` response
|
||||
type coupled with `XLSX.read` with type `"array"`:
|
||||
|
||||
```js
|
||||
$http({
|
||||
method:'GET',
|
||||
url:'https://sheetjs.com/pres.xlsx',
|
||||
responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
var wb = XLSX.read(data.data, {type:"array"});
|
||||
var d = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
||||
$scope.data = d;
|
||||
}, function(err) { console.log(err); });
|
||||
```
|
||||
|
||||
The HTML table can be directly exported with `XLSX.utils.table_to_book`:
|
||||
|
||||
```js
|
||||
var wb = XLSX.utils.table_to_book(document.getElementById('sjs-table'));
|
||||
XLSX.writeFile(wb, "export.xlsx");
|
||||
```
|
||||
|
||||
|
||||
## Import Directive
|
||||
|
||||
A general import directive is fairly straightforward:
|
||||
|
||||
- Define the `importSheetJs` directive in the app:
|
||||
|
||||
```js
|
||||
app.directive("importSheetJs", [SheetJSImportDirective]);
|
||||
```
|
||||
|
||||
- Add the attribute `import-sheet-js=""` to the file input element:
|
||||
|
||||
```html
|
||||
<input type="file" import-sheet-js="" multiple="false" />
|
||||
```
|
||||
|
||||
- Define the directive:
|
||||
|
||||
```js
|
||||
function SheetJSImportDirective() {
|
||||
return {
|
||||
scope: { opts: '=' },
|
||||
link: function ($scope, $elm) {
|
||||
$elm.on('change', function (changeEvent) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
/* read workbook */
|
||||
var ab = e.target.result;
|
||||
var workbook = XLSX.read(ab);
|
||||
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
};
|
||||
|
||||
reader.readAsArrayBuffer(changeEvent.target.files[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Export Service
|
||||
|
||||
An export can be triggered at any point! Depending on how data is represented,
|
||||
a workbook object can be built using the utility functions. For example, using
|
||||
an array of objects:
|
||||
|
||||
```js
|
||||
/* starting from this data */
|
||||
var data = [
|
||||
{ name: "Barack Obama", pres: 44 },
|
||||
{ name: "Donald Trump", pres: 45 }
|
||||
];
|
||||
|
||||
/* generate a worksheet */
|
||||
var ws = XLSX.utils.json_to_sheet(data);
|
||||
|
||||
/* add to workbook */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
|
||||
|
||||
/* write workbook and force a download */
|
||||
XLSX.writeFile(wb, "sheetjs.xlsx");
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
`grid.html` uses `angular-ui-grid` to display a table. The library does not
|
||||
provide any way to modify the import button, so the demo includes a simple
|
||||
directive for a HTML File Input control. It also includes a sample service for
|
||||
export which adds an item to the export menu.
|
||||
|
||||
The demo `SheetJSImportDirective` follows the prescription from the README for
|
||||
File input controls using `readAsArrayBuffer`, converting to a suitable
|
||||
representation and updating the scope.
|
||||
|
||||
`SheetJSExportService` exposes export functions for `XLSB` and `XLSX`. Other
|
||||
file formats can be exported by changing the `bookType` variable. It grabs
|
||||
values from the grid, builds an array of arrays, generates a workbook and forces
|
||||
a download. By setting the `filename` and `sheetname` options in the `ui-grid`
|
||||
options, the output can be controlled.
|
||||
The content has been reorganized;
|
||||
|
||||
- [The "Legacy Frameworks" section](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
|
||||
covers the AngularJS basics.
|
||||
- [The "Angular UI Grid" section](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
|
||||
covers the integration with Angular UI Grid.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
96
demos/angular/SheetJS-angular.js
vendored
96
demos/angular/SheetJS-angular.js
vendored
@ -1,96 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env browser */
|
||||
/* global XLSX */
|
||||
/* exported SheetJSExportService, SheetJSImportDirective */
|
||||
function SheetJSExportService(uiGridExporterService) {
|
||||
|
||||
function exportSheetJS(gridApi, wopts) {
|
||||
var columns = uiGridExporterService.getColumnHeaders(gridApi.grid, 'all');
|
||||
var data = uiGridExporterService.getData(gridApi.grid, 'all', 'all');
|
||||
|
||||
var fileName = gridApi.grid.options.filename || 'SheetJS';
|
||||
fileName += wopts.bookType ? "." + wopts.bookType : '.xlsx';
|
||||
|
||||
var sheetName = gridApi.grid.options.sheetname || 'Sheet1';
|
||||
|
||||
var wb = XLSX.utils.book_new(), ws = uigrid_to_sheet(data, columns);
|
||||
XLSX.utils.book_append_sheet(wb, ws, sheetName);
|
||||
XLSX.writeFile(wb, fileName);
|
||||
}
|
||||
|
||||
var service = {};
|
||||
service.exportXLSB = function exportXLSB(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsb', bookSST: true, type: 'array' }); };
|
||||
service.exportXLSX = function exportXLSX(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsx', bookSST: true, type: 'array' }); }
|
||||
|
||||
return service;
|
||||
|
||||
/* utilities */
|
||||
function uigrid_to_sheet(data, columns) {
|
||||
var o = [], oo = [], i = 0, j = 0;
|
||||
|
||||
/* column headers */
|
||||
for(j = 0; j < columns.length; ++j) oo.push(get_value(columns[j]));
|
||||
o.push(oo);
|
||||
|
||||
/* table data */
|
||||
for(i = 0; i < data.length; ++i) {
|
||||
oo = [];
|
||||
for(j = 0; j < data[i].length; ++j) oo.push(get_value(data[i][j]));
|
||||
o.push(oo);
|
||||
}
|
||||
/* aoa_to_sheet converts an array of arrays into a worksheet object */
|
||||
return XLSX.utils.aoa_to_sheet(o);
|
||||
}
|
||||
|
||||
function get_value(col) {
|
||||
if(!col) return col;
|
||||
if(col.value) return col.value;
|
||||
if(col.displayName) return col.displayName;
|
||||
if(col.name) return col.name;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function SheetJSImportDirective() {
|
||||
return {
|
||||
scope: { opts: '=' },
|
||||
link: function($scope, $elm) {
|
||||
$elm.on('change', function(changeEvent) {
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
/* read workbook */
|
||||
var ab = e.target.result;
|
||||
var wb = XLSX.read(ab);
|
||||
|
||||
/* grab first sheet */
|
||||
var wsname = wb.SheetNames[0];
|
||||
var ws = wb.Sheets[wsname];
|
||||
|
||||
/* grab first row and generate column headers */
|
||||
var aoa = XLSX.utils.sheet_to_json(ws, {header:1, raw:false});
|
||||
var cols = [];
|
||||
for(var i = 0; i < aoa[0].length; ++i) cols[i] = { field: aoa[0][i] };
|
||||
|
||||
/* generate rest of the data */
|
||||
var data = [];
|
||||
for(var r = 1; r < aoa.length; ++r) {
|
||||
data[r-1] = {};
|
||||
for(i = 0; i < aoa[r].length; ++i) {
|
||||
if(aoa[r][i] == null) continue;
|
||||
data[r-1][aoa[0][i]] = aoa[r][i];
|
||||
}
|
||||
}
|
||||
|
||||
/* update scope */
|
||||
$scope.$apply(function() {
|
||||
$scope.opts.columnDefs = cols;
|
||||
$scope.opts.data = data;
|
||||
});
|
||||
};
|
||||
|
||||
reader.readAsArrayBuffer(changeEvent.target.files[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
45
demos/angular/app.js
vendored
45
demos/angular/app.js
vendored
@ -1,45 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env browser */
|
||||
/* global angular, SheetJSExportService, SheetJSImportDirective */
|
||||
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.selection', 'ui.grid.exporter']);
|
||||
|
||||
/* Inject SheetJSExportService */
|
||||
app.factory('SheetJSExportService', SheetJSExportService);
|
||||
SheetJSExportService.inject = ['uiGridExporterService'];
|
||||
|
||||
app.controller('MainCtrl', ['$scope', '$http','SheetJSExportService', function($scope, $http, SheetJSExportService) {
|
||||
$scope.gridOptions = {
|
||||
columnDefs: [
|
||||
{ field: 'name' },
|
||||
{ field: 'gender', visible: false},
|
||||
{ field: 'company' }
|
||||
],
|
||||
enableGridMenu: true,
|
||||
enableSelectAll: true,
|
||||
exporterMenuPdf: false,
|
||||
exporterMenuCsv: false,
|
||||
showHeader: true,
|
||||
onRegisterApi: function(gridApi){
|
||||
$scope.gridApi = gridApi;
|
||||
},
|
||||
/* SheetJS Service setup */
|
||||
filename: "SheetJSAngular",
|
||||
sheetname: "ng-SheetJS",
|
||||
gridMenuCustomItems: [
|
||||
{
|
||||
title: 'Export all data as XLSX',
|
||||
action: function() { SheetJSExportService.exportXLSX($scope.gridApi); },
|
||||
order: 200
|
||||
},
|
||||
{
|
||||
title: 'Export all data as XLSB',
|
||||
action: function() { SheetJSExportService.exportXLSB($scope.gridApi); },
|
||||
order: 201
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json').success(function(data) { $scope.gridOptions.data = data; });
|
||||
|
||||
}]);
|
||||
app.directive("importSheetJs", [SheetJSImportDirective]);
|
@ -1,64 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html ng-app="app">
|
||||
<head>
|
||||
<title>SheetJS + AngularJS + ui-grid</title>
|
||||
<!-- Angular -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-touch.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-animate.js"></script>
|
||||
|
||||
<!-- ui-grid -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.11.0/ui-grid.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.11.0/ui-grid.css"/>
|
||||
|
||||
<!-- SheetJS js-xlsx library -->
|
||||
<script src="shim.js"></script>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
|
||||
<!-- SheetJS Service -->
|
||||
<script src="SheetJS-angular.js"></script>
|
||||
|
||||
<style>
|
||||
.grid1 {
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
};
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS + AngularJS demo</a></b>
|
||||
|
||||
The core library can be used as-is in AngularJS applications.
|
||||
The <a href="https://github.com/sheetjs/js-xlsx">Community Edition README</a> details some common use cases.
|
||||
We also have some <a href="http://sheetjs.com/demos/">more public demos</a>
|
||||
|
||||
This demo shows:
|
||||
- SheetJSExportService: a service for exporting data from a ui-grid
|
||||
- SheetJSImportDirective: a directive providing a file input button for import
|
||||
|
||||
<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
|
||||
</pre>
|
||||
|
||||
<div ng-controller="MainCtrl">
|
||||
<input type="file" import-sheet-js="" opts="gridOptions" multiple="false" />
|
||||
<div id="grid1" ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid"></div>
|
||||
</div>
|
||||
|
||||
<script src="app.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* eslint no-use-before-define:0 */
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,75 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html ng-app="sjs">
|
||||
<head>
|
||||
<title>SheetJS + AngularJS</title>
|
||||
<!-- Angular -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
|
||||
|
||||
<!-- SheetJS js-xlsx library -->
|
||||
<script src="shim.js"></script>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS + AngularJS demo</a></b>
|
||||
|
||||
The core library can be used as-is in AngularJS applications.
|
||||
The <a href="https://github.com/sheetjs/js-xlsx">Community Edition README</a> details some common use cases.
|
||||
We also have some <a href="http://sheetjs.com/demos/">more public demos</a>
|
||||
|
||||
This demo shows:
|
||||
- $http request for XLSX file and scope update with data
|
||||
- HTML table using ng-repeat
|
||||
- XLSX table export using `XLSX.utils.table_to_book`
|
||||
|
||||
<a href="https://sheetjs.com/pres.xlsx">Sample Spreadsheet</a>
|
||||
</pre>
|
||||
|
||||
<div ng-controller="sheetjs">
|
||||
|
||||
<table id="sjs-table">
|
||||
<tr><th>Name</th><th>Index</th></tr>
|
||||
<tr ng-repeat="row in data">
|
||||
<td>{{row.Name}}</td>
|
||||
<td>{{row.Index}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<button id="exportbtn">Export Table</button>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var app = angular.module('sjs', []);
|
||||
app.controller('sheetjs', function($scope, $http) {
|
||||
$http({
|
||||
method:'GET',
|
||||
url:'https://sheetjs.com/pres.xlsx',
|
||||
responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
var wb = XLSX.read(data.data, {type:"array"});
|
||||
var d = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
||||
$scope.data = d;
|
||||
}, function(err) { console.log(err); });
|
||||
});
|
||||
exportbtn.addEventListener('click', function() {
|
||||
var wb = XLSX.utils.table_to_book(document.getElementById('sjs-table'));
|
||||
XLSX.writeFile(wb, "export.xlsx");
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
/* eslint no-use-before-define:0 */
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1
demos/angular/shim.js
vendored
1
demos/angular/shim.js
vendored
@ -1 +0,0 @@
|
||||
../../shim.js
|
1
demos/angular/xlsx.core.min.js
vendored
1
demos/angular/xlsx.core.min.js
vendored
@ -1 +0,0 @@
|
||||
../../dist/xlsx.core.min.js
|
1
demos/angular/xlsx.full.min.js
vendored
1
demos/angular/xlsx.full.min.js
vendored
@ -1 +0,0 @@
|
||||
../../dist/xlsx.full.min.js
|
4
demos/browserify/.gitignore
vendored
4
demos/browserify/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
browserify.js
|
||||
browserify.min.js
|
||||
worker.js
|
||||
worker.min.js
|
2
demos/chrome/.gitignore
vendored
2
demos/chrome/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
xlsx.*.js
|
||||
logo.png
|
@ -1,8 +0,0 @@
|
||||
.PHONY: init
|
||||
init:
|
||||
cp ../../dist/xlsx.full.min.js .
|
||||
if [ ! -e logo.png ]; then curl -O https://sheetjs.com/logo.png; fi
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
eslint content.js popup.js table.js
|
@ -1,89 +1,6 @@
|
||||
# Chrome and Chromium
|
||||
|
||||
This library is compatible with Chrome and Chromium extensions and should just
|
||||
work out of the box. Specific API support is listed in the Chrome extensions
|
||||
API documentation.
|
||||
|
||||
## Generating Downloads
|
||||
|
||||
The `writeFile` function works in a Chrome or Chromium extension:
|
||||
|
||||
```js
|
||||
XLSX.writeFile(wb, "export.xlsx");
|
||||
```
|
||||
|
||||
Under the hood, it uses the `chrome.downloads` API. `"downloads"` permission
|
||||
should be set in `manifest.json`:
|
||||
|
||||
```js
|
||||
"permissions": [
|
||||
"downloads"
|
||||
]
|
||||
```
|
||||
|
||||
## Content Script Table Scraping
|
||||
|
||||
`table_to_book` and `table_to_sheet` can help build workbooks from DOM tables:
|
||||
|
||||
```js
|
||||
var tables = document.getElementsByTagName("table");
|
||||
var wb = XLSX.utils.book_new();
|
||||
for(var i = 0; i < tables.length; ++i) {
|
||||
var ws = XLSX.utils.table_to_sheet(tables[i]);
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Table" + i);
|
||||
}
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
The demo extension includes multiple features to demonstrate sample usage.
|
||||
Production extensions should include proper error handling.
|
||||
|
||||
#### Table Exporter
|
||||
|
||||
The `content.js` content script converts a table in the DOM to workbook object
|
||||
using the `table_to_book` utility function:
|
||||
|
||||
```js
|
||||
// event page script trigger
|
||||
chrome.tabs.sendMessage(tab.id);
|
||||
// content script convert
|
||||
var wb = XLSX.utils.table_to_book(elt);
|
||||
// event page script callback
|
||||
XLSX.writeFile(wb, "export.xlsx");
|
||||
```
|
||||
|
||||
Since the workbook object is a plain JS object, the object is sent back to an
|
||||
event page script which generates the file and attempts a download.
|
||||
|
||||
#### Bookmark Exporter
|
||||
|
||||
`chrome.bookmarks` API enables bookmark tree traversal. The "Export Bookmarks"
|
||||
button in the extension pop-up recursively walks the bookmark tree, pushes the
|
||||
bookmark URLs into a data array, and exports into a simple spreadsheet:
|
||||
|
||||
```js
|
||||
/* walk the bookmark tree */
|
||||
function recurse_bookmarks(data, tree) {
|
||||
if(tree.url) data.push({Name: tree.title, Location: tree.url});
|
||||
(tree.children||[]).forEach(function(child) { recurse_bookmarks(data, child); });
|
||||
}
|
||||
|
||||
/* get bookmark data */
|
||||
chrome.bookmarks.getTree(function(res) {
|
||||
/* load into an array */
|
||||
var data = [];
|
||||
res.forEach(function(t) { recurse_bookmarks(data, t); });
|
||||
|
||||
/* create worksheet */
|
||||
var ws = XLSX.utils.json_to_sheet(data, { header: ['Name', 'Location'] });
|
||||
|
||||
/* create workbook and export */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Bookmarks');
|
||||
XLSX.writeFile(wb, "bookmarks.xlsx");
|
||||
});
|
||||
```
|
||||
|
||||
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/chromium)
|
||||
includes more up-to-date details.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -1,27 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env browser */
|
||||
/* global XLSX, chrome */
|
||||
var coords = [0,0];
|
||||
document.addEventListener('mousedown', function(mouse) {
|
||||
if(mouse && mouse.button == 2) coords = [mouse.clientX, mouse.clientY];
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(msg, sender, cb) {
|
||||
if(!msg || !msg['Sheet']) return;
|
||||
if(msg.Sheet == "JS") {
|
||||
var elt = document.elementFromPoint(coords[0], coords[1]);
|
||||
while(elt != null) {
|
||||
if(elt.tagName.toLowerCase() == "table") return cb(XLSX.utils.table_to_book(elt));
|
||||
elt = elt.parentElement;
|
||||
}
|
||||
} else if(msg.Sheet == "J5") {
|
||||
var tables = document.getElementsByTagName("table");
|
||||
var wb = XLSX.utils.book_new();
|
||||
for(var i = 0; i < tables.length; ++i) {
|
||||
var ws = XLSX.utils.table_to_sheet(tables[i]);
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Table" + i);
|
||||
}
|
||||
return cb(wb);
|
||||
}
|
||||
cb(coords);
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "SheetJS Demo",
|
||||
"description": "Sample Extension using SheetJS to interact with Chrome",
|
||||
"version": "0.0.1",
|
||||
"browser_action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_icon": "logo.png"
|
||||
},
|
||||
"background": {
|
||||
"scripts": ["xlsx.full.min.js", "table.js"],
|
||||
"persistent": false
|
||||
},
|
||||
"content_scripts": [{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content.js", "xlsx.full.min.js"],
|
||||
"run_at": "document_end"
|
||||
}],
|
||||
"icons": {
|
||||
"16": "logo.png"
|
||||
},
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"<all_urls>",
|
||||
"bookmarks",
|
||||
"contextMenus",
|
||||
"downloads",
|
||||
"tabs"
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<title>SheetJS Chrome Extension Export Test</title>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- SheetJS js-xlsx library -->
|
||||
<script type="text/javascript" src="xlsx.full.min.js"></script>
|
||||
|
||||
<button type="button" id="sjsdownload">Export Bookmarks</button>
|
||||
<a><div id="sjsversion">Version</div></a>
|
||||
|
||||
<script type="text/javascript" src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,31 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env browser */
|
||||
/* global XLSX, chrome */
|
||||
document.getElementById('sjsversion').innerText = "SheetJS " + XLSX.version;
|
||||
|
||||
document.getElementById('sjsversion').addEventListener('click', function() {
|
||||
chrome.tabs.create({url: "https://sheetjs.com/"}); return false;
|
||||
});
|
||||
|
||||
/* recursively walk the bookmark tree */
|
||||
function recurse_bookmarks(data, tree, path) {
|
||||
if(tree.url) data.push({Name: tree.title, Location: tree.url, Path:path});
|
||||
var T = path ? (path + "::" + tree.title) : tree.title;
|
||||
(tree.children||[]).forEach(function(C) { recurse_bookmarks(data, C, T); });
|
||||
}
|
||||
|
||||
/* export bookmark data */
|
||||
document.getElementById('sjsdownload').addEventListener('click', function() {
|
||||
chrome.bookmarks.getTree(function(res) {
|
||||
var data = [];
|
||||
res.forEach(function(t) { recurse_bookmarks(data, t, ""); });
|
||||
|
||||
/* create worksheet */
|
||||
var ws = XLSX.utils.json_to_sheet(data, { header: ['Name', 'Location', 'Path'] });
|
||||
|
||||
/* create workbook and export */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Bookmarks');
|
||||
XLSX.writeFile(wb, "bookmarks.xlsx");
|
||||
});
|
||||
});
|
@ -1,43 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env browser */
|
||||
/* global XLSX, chrome */
|
||||
chrome.runtime.onInstalled.addListener(function() {
|
||||
chrome.contextMenus.create({
|
||||
type: "normal",
|
||||
id: "sjsexport",
|
||||
title: "Export Table to XLSX",
|
||||
contexts: ["page", "selection"]
|
||||
});
|
||||
chrome.contextMenus.create({
|
||||
type: "normal",
|
||||
id: "sj5export",
|
||||
title: "Export All Tables in Page",
|
||||
contexts: ["page", "selection"]
|
||||
});
|
||||
chrome.contextMenus.onClicked.addListener(function(info/*, tab*/) {
|
||||
var mode = "";
|
||||
switch(info.menuItemId) {
|
||||
case 'sjsexport': mode = "JS"; break;
|
||||
case 'sj5export': mode = "J5"; break;
|
||||
default: return;
|
||||
}
|
||||
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
|
||||
chrome.tabs.sendMessage(tabs[0].id, {Sheet:mode}, sjsexport_cb);
|
||||
});
|
||||
});
|
||||
|
||||
chrome.contextMenus.create({
|
||||
id: "sjsabout",
|
||||
title: "About",
|
||||
contexts: ["browser_action"]
|
||||
});
|
||||
chrome.contextMenus.onClicked.addListener(function(info/*, tab*/) {
|
||||
if(info.menuItemId !== "sjsabout") return;
|
||||
chrome.tabs.create({url: "https://sheetjs.com/"});
|
||||
});
|
||||
});
|
||||
|
||||
function sjsexport_cb(wb) {
|
||||
if(!wb || !wb.SheetNames || !wb.Sheets) { return alert("Error in exporting table"); }
|
||||
XLSX.writeFile(wb, "export.xlsx");
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"env": { "shared-node-browser":true },
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
},
|
||||
"plugins": [ "html", "json" ]
|
||||
}
|
1
demos/database/.gitignore
vendored
1
demos/database/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*.db
|
@ -1,89 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Firebase Dump Demo</title>
|
||||
<style>
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<h3><a href="//sheetjs.com/">SheetJS</a> Firebase Dump Demo</h3>
|
||||
<b>Example Code</b>
|
||||
|
||||
/* ... connect to firebase */
|
||||
const database = firebase.database();
|
||||
|
||||
/* import workbook */
|
||||
await database.ref('foo').set(workbook);
|
||||
|
||||
/* change cells */
|
||||
database.ref('foo').update({
|
||||
"Sheets/Sheet1/A1": {"t": "s", "v": "J"},
|
||||
"Sheets/Sheet1/A2": {"t": "n", "v": 5},
|
||||
});
|
||||
|
||||
/* export snapshot */
|
||||
const val = await database.ref('foo').once('value').val();
|
||||
XLSX.writeFile(wb, "firebase.xlsx");
|
||||
|
||||
</pre>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase.js"></script>
|
||||
<script>
|
||||
const Firebase = firebase;
|
||||
const config = {
|
||||
credential: {
|
||||
getAccessToken: () => ({
|
||||
expires_in: 0,
|
||||
access_token: '',
|
||||
}),
|
||||
},
|
||||
databaseURL: 'ws://localhost:5555'
|
||||
};
|
||||
|
||||
/* make new workbook object from CSV */
|
||||
const wb = XLSX.read('a,b,c\n1,2,3', {type:"binary"});
|
||||
|
||||
let P = Promise.resolve("sheetjs");
|
||||
|
||||
/* Connect to Firebase server and initialize collection */
|
||||
P = P.then(async () => {
|
||||
Firebase.initializeApp(config);
|
||||
const database = Firebase.database();
|
||||
await database.ref('foo').set(null);
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Insert entire workbook object into `foo` ref */
|
||||
P = P.then(async ([database]) => {
|
||||
await database.ref('foo').set(wb);
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Change cell A1 of Sheet1 to "J" and change A2 to 5 */
|
||||
P = P.then(async ([database]) => {
|
||||
database.ref('foo').update({
|
||||
"Sheets/Sheet1/A1": {"t": "s", "v": "J"},
|
||||
"Sheets/Sheet1/A2": {"t": "n", "v": 5},
|
||||
});
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Write to file */
|
||||
P = P.then(async ([database]) => {
|
||||
const val = await database.ref('foo').once('value');
|
||||
const wb = await val.val();
|
||||
XLSX.writeFile(wb, "firebase.xlsx");
|
||||
console.log(csv);
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Close connection */
|
||||
P = P.then(async ([database]) => { database.app.delete(); });
|
||||
|
||||
</script>
|
||||
</body>
|
@ -1,58 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
const XLSX = require('xlsx');
|
||||
const assert = require('assert');
|
||||
const Firebase = require('firebase-admin');
|
||||
|
||||
const config = {
|
||||
credential: {
|
||||
getAccessToken: () => ({
|
||||
expires_in: 0,
|
||||
access_token: '',
|
||||
}),
|
||||
},
|
||||
databaseURL: 'ws://localhost:5555'
|
||||
};
|
||||
|
||||
/* make new workbook object from CSV */
|
||||
const wb = XLSX.read('a,b,c\n1,2,3', {type:"binary", raw:true});
|
||||
|
||||
let P = Promise.resolve("sheetjs");
|
||||
|
||||
/* Connect to Firebase server and initialize collection */
|
||||
P = P.then(async () => {
|
||||
Firebase.initializeApp(config);
|
||||
const database = Firebase.database();
|
||||
await database.ref('foo').set(null);
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Insert entire workbook object into `foo` ref */
|
||||
P = P.then(async ([database]) => {
|
||||
await database.ref('foo').set(wb);
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Change cell A1 of Sheet1 to "J" and change A2 to 5 */
|
||||
P = P.then(async ([database]) => {
|
||||
database.ref('foo').update({
|
||||
"Sheets/Sheet1/A1": {"t": "s", "v": "J"},
|
||||
"Sheets/Sheet1/A2": {"t": "n", "v": 5},
|
||||
});
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Write to file */
|
||||
P = P.then(async ([database]) => {
|
||||
const val = await database.ref('foo').once('value');
|
||||
const wb = await val.val();
|
||||
XLSX.writeFile(wb, "firebase.xlsx");
|
||||
const ws = XLSX.readFile("firebase.xlsx").Sheets.Sheet1;
|
||||
const csv = XLSX.utils.sheet_to_csv(ws);
|
||||
assert.equal(csv, "J,b,c\n5,2,3\n");
|
||||
console.log(csv);
|
||||
return [database];
|
||||
});
|
||||
|
||||
/* Close connection */
|
||||
P = P.then(async ([database]) => { database.app.delete(); });
|
@ -1,73 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* global Promise */
|
||||
const XLSX = require('xlsx');
|
||||
const assert = require('assert');
|
||||
const SheetJSKnex = require("./SheetJSKnex");
|
||||
const Knex = require('knex');
|
||||
|
||||
/* Connection to both databases are passed around */
|
||||
let P = Promise.resolve([
|
||||
Knex({ client: 'sqlite3', connection: { filename: './knex1.db' } }),
|
||||
Knex({ client: 'sqlite3', connection: { filename: './knex2.db' } })
|
||||
]);
|
||||
|
||||
/* Sample data table */
|
||||
P = P.then(async (_) => {
|
||||
const [knex] = _;
|
||||
await knex.schema.dropTableIfExists('pres');
|
||||
await knex.schema.createTable('pres', (table) => {
|
||||
table.string('name');
|
||||
table.integer('idx');
|
||||
});
|
||||
await knex.insert([
|
||||
{ name: "Barack Obama", idx: 44 },
|
||||
{ name: "Donald Trump", idx: 45 }
|
||||
]).into('pres');
|
||||
|
||||
await knex.schema.dropTableIfExists('fmts');
|
||||
await knex.schema.createTable('fmts', (table) => {
|
||||
table.string('ext');
|
||||
table.string('ctr');
|
||||
table.integer('multi');
|
||||
});
|
||||
await knex.insert([
|
||||
{ ext: 'XLSB', ctr: 'ZIP', multi: 1 },
|
||||
{ ext: 'XLS', ctr: 'CFB', multi: 1 },
|
||||
{ ext: 'XLML', ctr: '', multi: 1 },
|
||||
{ ext: 'CSV', ctr: 'ZIP', multi: 0 },
|
||||
]).into('fmts');
|
||||
|
||||
return _;
|
||||
});
|
||||
|
||||
/* Export database to XLSX */
|
||||
P = P.then(async (_) => {
|
||||
const [knex] = _;
|
||||
const wb = XLSX.utils.book_new();
|
||||
await SheetJSKnex.book_append_knex(wb, knex, "pres");
|
||||
await SheetJSKnex.book_append_knex(wb, knex, "fmts");
|
||||
XLSX.writeFile(wb, "knex.xlsx");
|
||||
return _;
|
||||
});
|
||||
|
||||
/* Import XLSX to database */
|
||||
P = P.then(async (_) => {
|
||||
const [, knex] = _;
|
||||
const wb = XLSX.readFile("knex.xlsx");
|
||||
await SheetJSKnex.wb_to_knex(wb, knex);
|
||||
return _;
|
||||
});
|
||||
|
||||
/* Compare databases */
|
||||
P = P.then(async (_) => {
|
||||
const [k1, k2] = _;
|
||||
const P1 = await k1.select("*").from('pres');
|
||||
const P2 = await k2.select("*").from('pres');
|
||||
const F1 = await k1.select("*").from('fmts');
|
||||
const F2 = await k2.select("*").from('fmts');
|
||||
assert.deepEqual(P1, P2);
|
||||
assert.deepEqual(F1, F2);
|
||||
});
|
||||
|
||||
P.then(async () => { process.exit(); });
|
@ -1,59 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Live Demo</title>
|
||||
<style>
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS LocalStorage Demo</a></b>
|
||||
<pre id="data_">
|
||||
Original Data:
|
||||
</pre>
|
||||
<pre id="out">
|
||||
Output:
|
||||
|
||||
</pre>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
<script src="ObjUtils.js"></script>
|
||||
<script src="https://unpkg.com/localforage/dist/localforage.min.js"></script>
|
||||
<script src="SheetJSForage.js"></script>
|
||||
<script>
|
||||
/* eslint-env browser */
|
||||
/*global XLSX, localforage */
|
||||
var data = {
|
||||
"title": "SheetDB",
|
||||
"metadata": {
|
||||
"author": "SheetJS",
|
||||
"code": 7262
|
||||
},
|
||||
"data": [
|
||||
{ "Name": "Barack Obama", "Index": 44 },
|
||||
{ "Name": "Donald Trump", "Index": 45 },
|
||||
]
|
||||
};
|
||||
document.getElementById("data_").innerText += JSON.stringify(data, 2, 2);
|
||||
|
||||
localforage.setDriver(localforage.INDEXEDDB);
|
||||
(async function() {
|
||||
await localforage.clear();
|
||||
|
||||
await localforage.load(data);
|
||||
var wb = await localforage.dump();
|
||||
console.log(wb);
|
||||
|
||||
var OUT = document.getElementById("out");
|
||||
wb.SheetNames.forEach(function(n, i) {
|
||||
OUT.innerText += "Sheet " + i + " (" + n + ")\n";
|
||||
OUT.innerText += XLSX.utils.sheet_to_csv(wb.Sheets[n]);
|
||||
OUT.innerText += "\n";
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,57 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Live Demo</title>
|
||||
<style>
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS LocalStorage Demo</a></b>
|
||||
<pre id="data_">
|
||||
Original Data:
|
||||
</pre>
|
||||
<pre id="out">
|
||||
Output:
|
||||
|
||||
</pre>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
<script src="ObjUtils.js"></script>
|
||||
<script src="SheetJSStorage.js"></script>
|
||||
<script>
|
||||
/* eslint-env browser */
|
||||
/*global XLSX */
|
||||
var data = {
|
||||
"title": "SheetDB",
|
||||
"metadata": {
|
||||
"author": "SheetJS",
|
||||
"code": 7262
|
||||
},
|
||||
"data": [
|
||||
{ "Name": "Barack Obama", "Index": 44 },
|
||||
{ "Name": "Donald Trump", "Index": 45 },
|
||||
]
|
||||
};
|
||||
document.getElementById("data_").innerText += JSON.stringify(data, 2, 2);
|
||||
|
||||
(function() {
|
||||
localStorage.clear();
|
||||
|
||||
localStorage.load(data);
|
||||
var wb = localStorage.dump();
|
||||
console.log(wb);
|
||||
|
||||
var OUT = document.getElementById("out");
|
||||
wb.SheetNames.forEach(function(n, i) {
|
||||
OUT.innerText += "Sheet " + i + " (" + n + ")\n";
|
||||
OUT.innerText += XLSX.utils.sheet_to_csv(wb.Sheets[n]);
|
||||
OUT.innerText += "\n";
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,23 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var low = require('lowdb');
|
||||
var SheetJSAdapter = require('./SheetJSLowDB');
|
||||
var adapter = new SheetJSAdapter();
|
||||
var db = low(adapter);
|
||||
|
||||
db.defaults({ posts: [], user: {}, count: 0 }).write();
|
||||
db.get('posts').push({ id: 1, title: 'lowdb is awesome'}).write();
|
||||
db.set('user.name', 'typicode').write();
|
||||
db.update('count', function(n) { return n + 1; }).write();
|
||||
|
||||
adapter.dumpFile('ldb1.xlsx');
|
||||
|
||||
var adapter2 = new SheetJSAdapter();
|
||||
adapter2.loadFile('ldb1.xlsx');
|
||||
var db2 = low(adapter2);
|
||||
|
||||
db2.get('posts').push({ id: 2, title: 'mongodb is not'}).write();
|
||||
db2.set('user.name', 'sheetjs').write();
|
||||
db2.update('count', function(n) { return n + 1; }).write();
|
||||
|
||||
adapter2.dumpFile('ldb2.xlsx');
|
@ -1,16 +0,0 @@
|
||||
.PHONY: init
|
||||
init:
|
||||
rm -f node_modules/xlsx
|
||||
mkdir -p node_modules
|
||||
cd node_modules; ln -s ../../../ xlsx; cd -
|
||||
rm -f xlsx.full.min.js
|
||||
ln -s ../../dist/xlsx.full.min.js
|
||||
|
||||
FILES=$(filter-out xlsx.full.min.js,$(wildcard *.js)) $(wildcard *.html)
|
||||
.PHONY: lint
|
||||
lint: $(FILES)
|
||||
eslint $(FILES)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.db *.xlsx *.csv
|
@ -1,63 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* global Promise */
|
||||
const XLSX = require('xlsx');
|
||||
const SheetJSMongo = require("./SheetJSMongo");
|
||||
const MongoClient = require('mongodb').MongoClient;
|
||||
|
||||
const url = 'mongodb://localhost:27017/sheetjs';
|
||||
const db_name = 'sheetjs';
|
||||
|
||||
let P = Promise.resolve("sheetjs");
|
||||
|
||||
/* Connect to mongodb server */
|
||||
P = P.then(async () => {
|
||||
const client = await MongoClient.connect(url,{ useUnifiedTopology: true });
|
||||
return [client];
|
||||
});
|
||||
|
||||
/* Sample data table */
|
||||
P = P.then(async ([client]) => {
|
||||
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 }
|
||||
], {ordered: true});
|
||||
|
||||
try { await db.collection('fmts').drop(); } catch(e) {}
|
||||
const fmts = db.collection('fmts');
|
||||
await fmts.insertMany([
|
||||
{ ext: 'XLSB', ctr: 'ZIP', multi: 1 },
|
||||
{ ext: 'XLS', ctr: 'CFB', multi: 1 },
|
||||
{ ext: 'XLML', multi: 1 },
|
||||
{ ext: 'CSV', ctr: 'ZIP', multi: 0 },
|
||||
], {ordered: true});
|
||||
|
||||
return [client, pres, fmts];
|
||||
});
|
||||
|
||||
/* Export database to XLSX */
|
||||
P = P.then(async ([client, pres, fmts]) => {
|
||||
const wb = XLSX.utils.book_new();
|
||||
await SheetJSMongo.book_append_mongo(wb, pres, "pres");
|
||||
await SheetJSMongo.book_append_mongo(wb, fmts, "fmts");
|
||||
XLSX.writeFile(wb, "mongocrud.xlsx");
|
||||
return [client, pres, fmts];
|
||||
});
|
||||
|
||||
/* Read the new file and dump all of the data */
|
||||
P = P.then(([client]) => {
|
||||
const wb = XLSX.readFile('mongocrud.xlsx');
|
||||
wb.SheetNames.forEach((n,i) => {
|
||||
console.log(`Sheet #${i+1}: ${n}`);
|
||||
const ws = wb.Sheets[n];
|
||||
console.log(XLSX.utils.sheet_to_csv(ws));
|
||||
});
|
||||
return [client];
|
||||
});
|
||||
|
||||
/* Close connection */
|
||||
P.then(async ([client]) => { client.close(); });
|
@ -1,54 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* global Promise */
|
||||
const XLSX = require('xlsx');
|
||||
const assert = require('assert');
|
||||
const MongoClient = require('mongodb').MongoClient;
|
||||
|
||||
const url = 'mongodb://localhost:27017/sheetjs';
|
||||
const db_name = 'sheetjs';
|
||||
|
||||
/* make new workbook object from CSV */
|
||||
const wb = XLSX.read('a,b,c\n1,2,3', {type:"binary", raw:true});
|
||||
|
||||
let P = Promise.resolve("sheetjs");
|
||||
|
||||
/* Connect to mongodb server and initialize collection */
|
||||
P = P.then(async () => {
|
||||
const client = await MongoClient.connect(url,{ useUnifiedTopology: true });
|
||||
const db = client.db(db_name);
|
||||
try { await db.collection('wb').drop(); } catch(e) {}
|
||||
const coll = db.collection('wb');
|
||||
return [client, coll];
|
||||
});
|
||||
|
||||
/* Insert entire workbook object as a document */
|
||||
P = P.then(async ([client, coll]) => {
|
||||
const res = await coll.insertOne(wb);
|
||||
assert.equal(res.insertedCount, 1);
|
||||
return [client, coll];
|
||||
});
|
||||
|
||||
/* Change cell A1 of Sheet1 to "J" and change A2 to 5 */
|
||||
P = P.then(async ([client, coll]) => {
|
||||
const res = await coll.updateOne({}, { $set: {
|
||||
"Sheets.Sheet1.A1": {"t": "s", "v": "J"},
|
||||
"Sheets.Sheet1.A2": {"t": "n", "v": 5},
|
||||
}});
|
||||
assert.equal(res.matchedCount, 1);
|
||||
assert.equal(res.modifiedCount, 1);
|
||||
return [client, coll];
|
||||
});
|
||||
|
||||
/* Write to file */
|
||||
P = P.then(async ([client, coll]) => {
|
||||
const res = await coll.find({}).toArray();
|
||||
const wb = res[0];
|
||||
XLSX.writeFile(wb, "mongo.xlsx");
|
||||
const ws = XLSX.readFile("mongo.xlsx").Sheets.Sheet1;
|
||||
console.log(XLSX.utils.sheet_to_csv(ws));
|
||||
return [client, coll];
|
||||
});
|
||||
|
||||
/* Close connection */
|
||||
P.then(async ([client]) => { client.close(); });
|
@ -1,70 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require('xlsx');
|
||||
var assert = require('assert');
|
||||
var SheetJSSQL = require('./SheetJSSQL');
|
||||
var mysql = require('mysql2/promise');
|
||||
|
||||
/* Connection options (requires two databases sheetjs and sheetj5) */
|
||||
var opts = {
|
||||
host : 'localhost',
|
||||
user : 'SheetJS',
|
||||
password : 'SheetJS',
|
||||
};
|
||||
|
||||
/* Sample data table */
|
||||
var init = [
|
||||
"DROP TABLE IF EXISTS pres",
|
||||
"CREATE TABLE pres (name TEXT, idx TINYINT)",
|
||||
"INSERT INTO pres VALUES ('Barack Obama', 44)",
|
||||
"INSERT INTO pres VALUES ('Donald Trump', 45)",
|
||||
"DROP TABLE IF EXISTS fmts",
|
||||
"CREATE TABLE fmts (ext TEXT, ctr TEXT, multi TINYINT)",
|
||||
"INSERT INTO fmts VALUES ('XLSB', 'ZIP', 1)",
|
||||
"INSERT INTO fmts VALUES ('XLS', 'CFB', 1)",
|
||||
"INSERT INTO fmts VALUES ('XLML', '', 1)",
|
||||
"INSERT INTO fmts VALUES ('CSV', '', 0)",
|
||||
];
|
||||
|
||||
(async () => {
|
||||
const conn1 = await mysql.createConnection(Object.assign({}, opts, {database: "sheetjs"}));
|
||||
for(var i = 0; i < init.length; ++i) await conn1.query(init[i]);
|
||||
|
||||
/* Export table to XLSX */
|
||||
var wb = XLSX.utils.book_new();
|
||||
|
||||
async function book_append_table(wb, name) {
|
||||
var r_f = await conn1.query('SELECT * FROM ' + name);
|
||||
var r = r_f[0];
|
||||
var ws = XLSX.utils.json_to_sheet(r);
|
||||
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||
}
|
||||
|
||||
await book_append_table(wb, "pres");
|
||||
await book_append_table(wb, "fmts");
|
||||
XLSX.writeFile(wb, "mysql.xlsx");
|
||||
|
||||
/* Capture first database info and close */
|
||||
var P1 = (await conn1.query("SELECT * FROM pres"))[0];
|
||||
var F1 = (await conn1.query("SELECT * FROM fmts"))[0];
|
||||
await conn1.close();
|
||||
|
||||
/* Import XLSX to table */
|
||||
const conn2 = await mysql.createConnection(Object.assign({}, opts, {database: "sheetj5"}));
|
||||
var wb2 = XLSX.readFile("mysql.xlsx");
|
||||
var queries = SheetJSSQL.book_to_sql(wb2, "MYSQL");
|
||||
for(i = 0; i < queries.length; ++i) await conn2.query(queries[i]);
|
||||
|
||||
/* Capture first database info and close */
|
||||
var P2 = (await conn2.query("SELECT * FROM pres"))[0];
|
||||
var F2 = (await conn2.query("SELECT * FROM fmts"))[0];
|
||||
await conn2.close();
|
||||
|
||||
/* Compare results */
|
||||
assert.deepEqual(P1, P2);
|
||||
assert.deepEqual(F1, F2);
|
||||
|
||||
/* Display results */
|
||||
console.log(P2);
|
||||
console.log(F2);
|
||||
})();
|
@ -1,59 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/*global XLSX, module, require */
|
||||
var ObjUtils = (function() {
|
||||
|
||||
var X;
|
||||
if(typeof XLSX !== "undefined") X = XLSX;
|
||||
else if(typeof require !== 'undefined') X = require('xlsx');
|
||||
else throw new Error("Could not find XLSX");
|
||||
|
||||
function walk(obj, key, arr) {
|
||||
if(Array.isArray(obj)) return;
|
||||
if(typeof obj != "object" || obj instanceof Date) { arr.push({path:key, value:obj}); return; }
|
||||
Object.keys(obj).forEach(function(k) {
|
||||
walk(obj[k], key ? key + "." + k : k, arr);
|
||||
});
|
||||
}
|
||||
|
||||
function object_to_workbook(obj) {
|
||||
var wb = X.utils.book_new();
|
||||
|
||||
var base = []; walk(obj, "", base);
|
||||
var ws = X.utils.json_to_sheet(base, {header:["path", "value"]});
|
||||
X.utils.book_append_sheet(wb, ws, "_keys");
|
||||
|
||||
Object.keys(obj).forEach(function(k) {
|
||||
if(!Array.isArray(obj[k])) return;
|
||||
X.utils.book_append_sheet(wb, X.utils.json_to_sheet(obj[k]), k);
|
||||
});
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
function deepset(obj, path, value) {
|
||||
if(path.indexOf(".") == -1) return obj[path] = value;
|
||||
var parts = path.split(".");
|
||||
if(!obj[parts[0]]) obj[parts[0]] = {};
|
||||
return deepset(obj[parts[0]], parts.slice(1).join("."), value);
|
||||
}
|
||||
function workbook_set_object(obj, wb) {
|
||||
var ws = wb.Sheets["_keys"]; if(ws) {
|
||||
var data = X.utils.sheet_to_json(ws, {raw:true});
|
||||
data.forEach(function(r) { deepset(obj, r.path, r.value); });
|
||||
}
|
||||
wb.SheetNames.forEach(function(n) {
|
||||
if(n == "_keys") return;
|
||||
obj[n] = X.utils.sheet_to_json(wb.Sheets[n], {raw:true});
|
||||
});
|
||||
}
|
||||
|
||||
function workbook_to_object(wb) { var obj = {}; workbook_set_object(obj, wb); return obj; }
|
||||
|
||||
return {
|
||||
workbook_to_object: workbook_to_object,
|
||||
object_to_workbook: object_to_workbook,
|
||||
workbook_set_object: workbook_set_object
|
||||
};
|
||||
})();
|
||||
|
||||
if(typeof module !== 'undefined') module.exports = ObjUtils;
|
@ -1,72 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require('xlsx');
|
||||
var assert = require('assert');
|
||||
var SheetJSSQL = require('./SheetJSSQL');
|
||||
var Client = require('pg').Client;
|
||||
|
||||
/* Connection options (requires two databases sheetjs and sheetj5) */
|
||||
var opts = {
|
||||
host : 'localhost',
|
||||
user : 'SheetJS',
|
||||
password : 'SheetJS',
|
||||
};
|
||||
|
||||
/* Sample data table */
|
||||
var init = [
|
||||
"DROP TABLE IF EXISTS pres",
|
||||
"CREATE TABLE pres (name text, idx smallint)",
|
||||
"INSERT INTO pres VALUES ('Barack Obama', 44)",
|
||||
"INSERT INTO pres VALUES ('Donald Trump', 45)",
|
||||
"DROP TABLE IF EXISTS fmts",
|
||||
"CREATE TABLE fmts (ext text, ctr text, multi smallint)",
|
||||
"INSERT INTO fmts VALUES ('XLSB', 'ZIP', 1)",
|
||||
"INSERT INTO fmts VALUES ('XLS', 'CFB', 1)",
|
||||
"INSERT INTO fmts VALUES ('XLML', '', 1)",
|
||||
"INSERT INTO fmts VALUES ('CSV', '', 0)",
|
||||
];
|
||||
|
||||
var conn1 = new Client(Object.assign({}, opts, {database: "sheetjs"}));
|
||||
var conn2 = new Client(Object.assign({}, opts, {database: "sheetj5"}));
|
||||
(async () => {
|
||||
await conn1.connect();
|
||||
for(var i = 0; i < init.length; ++i) await conn1.query(init[i]);
|
||||
|
||||
/* Export table to XLSX */
|
||||
var wb = XLSX.utils.book_new();
|
||||
|
||||
async function book_append_table(wb, name) {
|
||||
var r_f = await conn1.query('SELECT * FROM ' + name);
|
||||
var r = r_f.rows;
|
||||
var ws = XLSX.utils.json_to_sheet(r);
|
||||
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||
}
|
||||
|
||||
await book_append_table(wb, "pres");
|
||||
await book_append_table(wb, "fmts");
|
||||
XLSX.writeFile(wb, "pgsql.xlsx");
|
||||
|
||||
/* Capture first database info and close */
|
||||
var P1 = (await conn1.query("SELECT * FROM pres")).rows;
|
||||
var F1 = (await conn1.query("SELECT * FROM fmts")).rows;
|
||||
await conn1.end();
|
||||
|
||||
/* Import XLSX to table */
|
||||
await conn2.connect();
|
||||
var wb2 = XLSX.readFile("pgsql.xlsx");
|
||||
var queries = SheetJSSQL.book_to_sql(wb2, "PGSQL");
|
||||
for(i = 0; i < queries.length; ++i) { console.log(queries[i]); await conn2.query(queries[i]); }
|
||||
|
||||
/* Capture first database info and close */
|
||||
var P2 = (await conn2.query("SELECT * FROM pres")).rows;
|
||||
var F2 = (await conn2.query("SELECT * FROM fmts")).rows;
|
||||
await conn2.end();
|
||||
|
||||
/* Compare results */
|
||||
assert.deepEqual(P1, P2);
|
||||
assert.deepEqual(F1, F2);
|
||||
|
||||
/* Display results */
|
||||
console.log(P2);
|
||||
console.log(F2);
|
||||
})();
|
@ -1,340 +1,11 @@
|
||||
# Databases
|
||||
|
||||
"Database" is a catch-all term referring to traditional RDBMS as well as K/V
|
||||
stores, document databases, and other "NoSQL" storages. There are many external
|
||||
database systems as well as browser APIs like WebSQL and `localStorage`
|
||||
This demo has been split up for clarity:
|
||||
|
||||
This demo discusses general strategies and provides examples for a variety of
|
||||
database systems. The examples are merely intended to demonstrate very basic
|
||||
functionality.
|
||||
- <https://docs.sheetjs.com/docs/getting-started/demos/database> covers SQL and
|
||||
structured data (including CRUD operations)
|
||||
|
||||
|
||||
## Structured Tables
|
||||
|
||||
Database tables are a common import and export target for spreadsheets. One
|
||||
common representation of a database table is an array of JS objects whose keys
|
||||
are column headers and whose values are the underlying data values. For example,
|
||||
|
||||
| Name | Index |
|
||||
| :----------- | ----: |
|
||||
| Barack Obama | 44 |
|
||||
| Donald Trump | 45 |
|
||||
|
||||
is naturally represented as an array of objects
|
||||
|
||||
```js
|
||||
[
|
||||
{ Name: "Barack Obama", Index: 44 },
|
||||
{ Name: "Donald Trump", Index: 45 }
|
||||
]
|
||||
```
|
||||
|
||||
The `sheet_to_json` and `json_to_sheet` helper functions work with objects of
|
||||
similar shape, converting to and from worksheet objects. The corresponding
|
||||
worksheet would include a header row for the labels:
|
||||
|
||||
```
|
||||
XXX| A | B |
|
||||
---+--------------+-------+
|
||||
1 | Name | Index |
|
||||
2 | Barack Obama | 44 |
|
||||
3 | Donald Trump | 45 |
|
||||
```
|
||||
|
||||
|
||||
## Building Schemas from Worksheets
|
||||
|
||||
The `sheet_to_json` helper function generates arrays of JS objects that can be
|
||||
scanned to determine the column "types", and there are third-party connectors
|
||||
that can push arrays of JS objects to database tables.
|
||||
|
||||
The [`sql`](http://sheetjs.com/sql) browser demo uses WebSQL, which is
|
||||
limited to the SQLite fundamental types.
|
||||
|
||||
<details>
|
||||
<summary><b>Implementation details</b> (click to show)</summary>
|
||||
|
||||
The `sql` schema builder scans the first row to find headers:
|
||||
|
||||
```js
|
||||
if(!ws || !ws['!ref']) return;
|
||||
var range = XLSX.utils.decode_range(ws['!ref']);
|
||||
if(!range || !range.s || !range.e || range.s > range.e) return;
|
||||
var R = range.s.r, C = range.s.c;
|
||||
|
||||
var names = new Array(range.e.c-range.s.c+1);
|
||||
for(C = range.s.c; C<= range.e.c; ++C){
|
||||
var addr = XLSX.utils.encode_cell({c:C,r:R});
|
||||
names[C-range.s.c] = ws[addr] ? ws[addr].v : XLSX.utils.encode_col(C);
|
||||
}
|
||||
```
|
||||
|
||||
After finding the headers, a deduplication step ensures that data is not lost.
|
||||
Duplicate headers will be suffixed with `_1`, `_2`, etc.
|
||||
|
||||
```js
|
||||
for(var i = 0; i < names.length; ++i) if(names.indexOf(names[i]) < i)
|
||||
for(var j = 0; j < names.length; ++j) {
|
||||
var _name = names[i] + "_" + (j+1);
|
||||
if(names.indexOf(_name) > -1) continue;
|
||||
names[i] = _name;
|
||||
}
|
||||
```
|
||||
|
||||
A column-major walk helps determine the data type. For SQLite the only relevant
|
||||
data types are `REAL` and `TEXT`. If a string or date or error is seen in any
|
||||
value of a column, the column is marked as `TEXT`:
|
||||
|
||||
```js
|
||||
var types = new Array(range.e.c-range.s.c+1);
|
||||
for(C = range.s.c; C<= range.e.c; ++C) {
|
||||
var seen = {}, _type = "";
|
||||
for(R = range.s.r+1; R<= range.e.r; ++R)
|
||||
seen[(ws[XLSX.utils.encode_cell({c:C,r:R})]||{t:"z"}).t] = true;
|
||||
if(seen.s || seen.str) _type = "TEXT";
|
||||
else if(seen.n + seen.b + seen.d + seen.e > 1) _type = "TEXT";
|
||||
else switch(true) {
|
||||
case seen.b:
|
||||
case seen.n: _type = "REAL"; break;
|
||||
case seen.e: _type = "TEXT"; break;
|
||||
case seen.d: _type = "TEXT"; break;
|
||||
}
|
||||
types[C-range.s.c] = _type || "TEXT";
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
The included `SheetJSSQL.js` script demonstrates SQL statement generation.
|
||||
|
||||
|
||||
## Objects, K/V and "Schema-less" Databases
|
||||
|
||||
So-called "Schema-less" databases allow for arbitrary keys and values within the
|
||||
entries in the database. K/V stores and Objects add additional restrictions.
|
||||
|
||||
There is no natural way to translate arbitrarily shaped schemas to worksheets
|
||||
in a workbook. One common trick is to dedicate one worksheet to holding named
|
||||
keys. For example, considering the JS object:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "SheetDB",
|
||||
"metadata": {
|
||||
"author": "SheetJS",
|
||||
"code": 7262
|
||||
},
|
||||
"data": [
|
||||
{ "Name": "Barack Obama", "Index": 44 },
|
||||
{ "Name": "Donald Trump", "Index": 45 },
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
A dedicated worksheet should store the one-off named values:
|
||||
|
||||
```
|
||||
XXX| A | B |
|
||||
---+-----------------+---------+
|
||||
1 | Path | Value |
|
||||
2 | title | SheetDB |
|
||||
3 | metadata.author | SheetJS |
|
||||
4 | metadata.code | 7262 |
|
||||
```
|
||||
|
||||
The included `ObjUtils.js` script demonstrates object-workbook conversion:
|
||||
|
||||
<details>
|
||||
<summary><b>Implementation details</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
function deepset(obj, path, value) {
|
||||
if(path.indexOf(".") == -1) return obj[path] = value;
|
||||
var parts = path.split(".");
|
||||
if(!obj[parts[0]]) obj[parts[0]] = {};
|
||||
return deepset(obj[parts[0]], parts.slice(1).join("."), value);
|
||||
}
|
||||
function workbook_to_object(wb) {
|
||||
var out = {};
|
||||
|
||||
/* assign one-off keys */
|
||||
var ws = wb.Sheets["_keys"]; if(ws) {
|
||||
var data = XLSX.utils.sheet_to_json(ws, {raw:true});
|
||||
data.forEach(function(r) { deepset(out, r.path, r.value); });
|
||||
}
|
||||
|
||||
/* assign arrays from worksheet tables */
|
||||
wb.SheetNames.forEach(function(n) {
|
||||
if(n == "_keys") return;
|
||||
out[n] = XLSX.utils.sheet_to_json(wb.Sheets[n], {raw:true});
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function walk(obj, key, arr) {
|
||||
if(Array.isArray(obj)) return;
|
||||
if(typeof obj != "object") { arr.push({path:key, value:obj}); return; }
|
||||
Object.keys(obj).forEach(function(k) { walk(obj[k], key?key+"."+k:k, arr); });
|
||||
}
|
||||
function object_to_workbook(obj) {
|
||||
var wb = XLSX.utils.book_new();
|
||||
|
||||
/* keyed entries */
|
||||
var base = []; walk(obj, "", base);
|
||||
var ws = XLSX.utils.json_to_sheet(base, {header:["path", "value"]});
|
||||
XLSX.utils.book_append_sheet(wb, ws, "_keys");
|
||||
|
||||
/* arrays */
|
||||
Object.keys(obj).forEach(function(k) {
|
||||
if(!Array.isArray(obj[k])) return;
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(obj[k]), k);
|
||||
});
|
||||
|
||||
return wb;
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## Browser APIs
|
||||
|
||||
#### WebSQL
|
||||
|
||||
WebSQL is a popular SQL-based in-browser database available on Chrome. In
|
||||
practice, it is powered by SQLite, and most simple SQLite-compatible queries
|
||||
work as-is in WebSQL.
|
||||
|
||||
The public demo <http://sheetjs.com/sql> generates a database from workbook.
|
||||
|
||||
#### LocalStorage and SessionStorage
|
||||
|
||||
The Storage API, encompassing `localStorage` and `sessionStorage`, describes
|
||||
simple key-value stores that only support string values and keys. Objects can be
|
||||
stored as JSON using `JSON.stringify` and `JSON.parse` to set and get keys.
|
||||
|
||||
`SheetJSStorage.js` extends the `Storage` prototype with a `load` function to
|
||||
populate the db based on an object and a `dump` function to generate a workbook
|
||||
from the data in the storage. `LocalStorage.html` tests `localStorage`.
|
||||
|
||||
#### IndexedDB
|
||||
|
||||
IndexedDB is a more complex storage solution, but the `localForage` wrapper
|
||||
supplies a Promise-based interface mimicking the `Storage` API.
|
||||
|
||||
`SheetJSForage.js` extends the `localforage` object with a `load` function to
|
||||
populate the db based on an object and a `dump` function to generate a workbook
|
||||
from the data in the storage. `LocalForage.html` forces IndexedDB mode.
|
||||
|
||||
|
||||
## External Database Demos
|
||||
|
||||
### SQL Databases
|
||||
|
||||
There are nodejs connector libraries for all of the popular RDBMS systems. They
|
||||
have facilities for connecting to a database, executing queries, and obtaining
|
||||
results as arrays of JS objects that can be passed to `json_to_sheet`. The main
|
||||
differences surround API shape and supported data types.
|
||||
|
||||
#### SQLite
|
||||
|
||||
[The `better-sqlite3` module](https://www.npmjs.com/package/better-sqlite3)
|
||||
provides a very simple API for working with SQLite databases. `Statement#all`
|
||||
runs a prepared statement and returns an array of JS objects.
|
||||
|
||||
`SQLiteTest.js` generates a simple two-table SQLite database (`SheetJS1.db`),
|
||||
exports to XLSX (`sqlite.xlsx`), imports the new XLSX file to a new database
|
||||
(`SheetJS2.db`) and verifies the tables are preserved.
|
||||
|
||||
#### MySQL / MariaDB
|
||||
|
||||
[The `mysql2` module](https://www.npmjs.com/package/mysql2) supplies a callback
|
||||
API as well as a Promise wrapper. `Connection#query` runs a statement and
|
||||
returns an array whose first element is an array of JS objects.
|
||||
|
||||
`MySQLTest.js` connects to the MySQL instance running on `localhost`, builds two
|
||||
tables in the `sheetjs` database, exports to XLSX, imports the new XLSX file to
|
||||
the `sheetj5` database and verifies the tables are preserved.
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
[The `pg` module](https://node-postgres.com/) supplies a Promise wrapper.
|
||||
`Client#query` runs a statement and returns a result object. The `rows` key of
|
||||
the object is an array of JS objects.
|
||||
|
||||
`PgSQLTest.js` connects to the PostgreSQL server on `localhost`, builds two
|
||||
tables in the `sheetjs` database, exports to XLSX, imports the new XLSX file to
|
||||
the `sheetj5` database and verifies the tables are preserved.
|
||||
|
||||
#### Knex Query Builder
|
||||
|
||||
[The `knex` module](https://www.npmjs.com/package/knex) builds SQL queries. The
|
||||
same exact code can be used against Oracle Database, MSSQL, and other engines.
|
||||
|
||||
`KnexTest.js` uses the `sqlite3` connector and follows the same procedure as the
|
||||
SQLite test. The included `SheetJSKnex.js` script converts between the query
|
||||
builder and the common spreadsheet format.
|
||||
|
||||
### Key/Value Stores
|
||||
|
||||
#### Redis
|
||||
|
||||
Redis is a powerful data structure server that can store simple strings, sets,
|
||||
sorted sets, hashes and lists. One simple database representation stores the
|
||||
strings in a special worksheet (`_strs`), the manifest in another worksheet
|
||||
(`_manifest`), and each object in its own worksheet (`obj##`).
|
||||
|
||||
`RedisTest.js` connects to a local Redis server, populates data based on the
|
||||
official Redis tutorial, exports to XLSX, flushes the server, imports the new
|
||||
XLSX file and verifies the data round-tripped correctly. `SheetJSRedis.js`
|
||||
includes the implementation details.
|
||||
|
||||
#### LowDB
|
||||
|
||||
LowDB is a small schemaless database powered by `lodash`. `_.get` and `_.set`
|
||||
helper functions make storing metadata a breeze. The included `SheetJSLowDB.js`
|
||||
script demonstrates a simple adapter that can load and dump data.
|
||||
|
||||
### Document Databases
|
||||
|
||||
Since document databases are capable of holding more complex objects, they can
|
||||
actually hold the underlying worksheet objects! In some cases, where arrays are
|
||||
supported, they can even hold the workbook object.
|
||||
|
||||
#### MongoDB
|
||||
|
||||
MongoDB is a popular document-oriented database engine. `MongoDBTest.js` uses
|
||||
MongoDB to hold a simple workbook and export to XLSX.
|
||||
|
||||
`MongoDBCRUD.js` follows the SQL examples using an idiomatic collection
|
||||
structure. Exporting and importing collections are straightforward:
|
||||
|
||||
<details>
|
||||
<summary><b>Example code</b> (click to show)</summary>
|
||||
|
||||
```js
|
||||
/* generate a worksheet from a collection */
|
||||
const aoa = await db.collection('coll').find({}).toArray();
|
||||
aoa.forEach((x) => delete x._id);
|
||||
const ws = XLSX.utils.json_to_sheet(aoa);
|
||||
|
||||
|
||||
/* import data from a worksheet to a collection */
|
||||
const aoa = XLSX.utils.sheet_to_json(ws);
|
||||
await db.collection('coll').insertMany(aoa, {ordered: true});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### Firebase
|
||||
|
||||
[`firebase-server`](https://www.npmjs.com/package/firebase-server) is a simple
|
||||
mock Firebase server used in the tests, but the same code works in an external
|
||||
Firebase deployment when plugging in the database connection info.
|
||||
|
||||
`FirebaseDemo.html` and `FirebaseTest.js` demonstrate a whole-workbook process.
|
||||
The entire workbook object is persisted, a few cells are changed, and the stored
|
||||
data is dumped and exported to XLSX.
|
||||
- https://docs.sheetjs.com/docs/getting-started/demos/nosql covers unstructured
|
||||
data including "NoSQL" data stores.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -1,50 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require("xlsx");
|
||||
var SheetJSRedis = require("./SheetJSRedis");
|
||||
var assert = require('assert');
|
||||
var redis = require("redis"), util = require("util");
|
||||
var client = redis.createClient();
|
||||
|
||||
|
||||
/* Sample data */
|
||||
var init = [
|
||||
["FLUSHALL", []],
|
||||
["SADD", ["birdpowers", "flight", "pecking"]],
|
||||
["SET", ["foo", "bar"]],
|
||||
["SET", ["baz", 0]],
|
||||
["RPUSH", ["friends", "sam", "alice", "bob"]],
|
||||
["ZADD", ["hackers", 1906, 'Grace Hopper', 1912, 'Alan Turing', 1916, 'Claude Shannon', 1940, 'Alan Kay', 1953, 'Richard Stallman', 1957, 'Sophie Wilson', 1965, 'Yukihiro Matsumoto', 1969, 'Linus Torvalds']],
|
||||
["SADD", ["superpowers", "flight", 'x-ray vision']],
|
||||
["HMSET", ["user:1000", "name", 'John Smith', "email", 'john.smith@example.com', "password", "s3cret", "visits", 1]],
|
||||
["HMSET", ["user:1001", "name", 'Mary Jones', "email", 'mjones@example.com', "password", "hidden"]]
|
||||
];
|
||||
|
||||
const R = (()=>{
|
||||
const Rcache = {};
|
||||
const R_ = (n) => Rcache[n] || (Rcache[n] = util.promisify(client[n]).bind(client));
|
||||
return (n) => R_(n.toLowerCase());
|
||||
})();
|
||||
|
||||
(async () => {
|
||||
for(var i = 0; i < init.length; ++i) await R(init[i][0])(init[i][1]);
|
||||
|
||||
/* Export database to XLSX */
|
||||
var wb = await SheetJSRedis.redis_to_wb(R);
|
||||
XLSX.writeFile(wb, "redis.xlsx");
|
||||
|
||||
/* Import XLSX to database */
|
||||
await R("flushall")();
|
||||
var wb2 = XLSX.readFile("redis.xlsx");
|
||||
await SheetJSRedis.wb_to_redis(wb2, R);
|
||||
|
||||
/* Verify */
|
||||
assert.equal(await R("get")("foo"), "bar");
|
||||
assert.equal(await R("lindex")("friends", 1), "alice");
|
||||
assert.equal(await R("zscore")("hackers", "Claude Shannon"), 1916);
|
||||
assert.equal(await R("hget")("user:1000", "name"), "John Smith");
|
||||
assert.equal(await R("sismember")("superpowers", "flight"), "1");
|
||||
assert.equal(await R("sismember")("birdpowers", "pecking"), "1");
|
||||
|
||||
client.quit();
|
||||
})();
|
@ -1,51 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require('xlsx');
|
||||
var assert = require('assert');
|
||||
var SheetJSSQL = require('./SheetJSSQL');
|
||||
var Database = require('better-sqlite3');
|
||||
var db1 = new Database('SheetJS1.db');
|
||||
|
||||
/* Sample data table */
|
||||
var init = [
|
||||
"DROP TABLE IF EXISTS pres",
|
||||
"CREATE TABLE pres (name TEXT, idx INTEGER)",
|
||||
"INSERT INTO pres VALUES ('Barack Obama', 44)",
|
||||
"INSERT INTO pres VALUES ('Donald Trump', 45)",
|
||||
"DROP TABLE IF EXISTS fmts",
|
||||
"CREATE TABLE fmts (ext TEXT, ctr TEXT, multi INTEGER)",
|
||||
"INSERT INTO fmts VALUES ('XLSB', 'ZIP', 1)",
|
||||
"INSERT INTO fmts VALUES ('XLS', 'CFB', 1)",
|
||||
"INSERT INTO fmts VALUES ('XLML', '', 1)",
|
||||
"INSERT INTO fmts VALUES ('CSV', '', 0)",
|
||||
];
|
||||
db1.exec(init.join(";"));
|
||||
|
||||
/* Export database to XLSX */
|
||||
var wb = XLSX.utils.book_new();
|
||||
function book_append_table(wb, db, name) {
|
||||
var r = db.prepare('SELECT * FROM ' + name).all();
|
||||
var ws = XLSX.utils.json_to_sheet(r);
|
||||
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||
}
|
||||
book_append_table(wb, db1, "pres");
|
||||
book_append_table(wb, db1, "fmts");
|
||||
XLSX.writeFile(wb, "sqlite.xlsx");
|
||||
|
||||
/* Import XLSX to database */
|
||||
var db2 = new Database('SheetJS2.db');
|
||||
var wb2 = XLSX.readFile("sqlite.xlsx");
|
||||
var queries = SheetJSSQL.book_to_sql(wb2, "SQLITE");
|
||||
queries.forEach(function(q) { db2.exec(q); });
|
||||
|
||||
/* Compare databases */
|
||||
var P1 = db1.prepare("SELECT * FROM pres").all();
|
||||
var P2 = db2.prepare("SELECT * FROM pres").all();
|
||||
var F1 = db1.prepare("SELECT * FROM fmts").all();
|
||||
var F2 = db2.prepare("SELECT * FROM fmts").all();
|
||||
assert.deepEqual(P1, P2);
|
||||
assert.deepEqual(F1, F2);
|
||||
|
||||
console.log(P2);
|
||||
console.log(F2);
|
||||
|
@ -1,20 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/*global ObjUtils, localforage */
|
||||
localforage.load = async function foo(data) {
|
||||
var keys = Object.keys(data);
|
||||
for(var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i], val = JSON.stringify(data[keys[i]])
|
||||
await localforage.setItem(key, val);
|
||||
}
|
||||
};
|
||||
|
||||
localforage.dump = async function() {
|
||||
var obj = {};
|
||||
var length = await localforage.length();
|
||||
for(var i = 0; i < length; ++i) {
|
||||
var key = await this.key(i);
|
||||
var val = await this.getItem(key);
|
||||
obj[key] = JSON.parse(val);
|
||||
}
|
||||
return ObjUtils.object_to_workbook(obj);
|
||||
};
|
@ -1,78 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require("xlsx");
|
||||
|
||||
async function book_append_knex(wb, knex, tbl) {
|
||||
const aoo = await knex.select("*").from(tbl);
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(aoo), tbl);
|
||||
}
|
||||
|
||||
const TYPES = {
|
||||
b: "boolean",
|
||||
n: "float",
|
||||
t: "string",
|
||||
d: "dateTime"
|
||||
};
|
||||
async function ws_to_knex(ws, knex, n) {
|
||||
if(!ws || !ws['!ref']) return;
|
||||
var range = XLSX.utils.decode_range(ws['!ref']);
|
||||
if(!range || !range.s || !range.e || range.s > range.e) return;
|
||||
var R = range.s.r, C = range.s.c;
|
||||
|
||||
var names = new Array(range.e.c-range.s.c+1);
|
||||
for(C = range.s.c; C<= range.e.c; ++C){
|
||||
var addr = XLSX.utils.encode_cell({c:C,r:R});
|
||||
names[C-range.s.c] = ws[addr] ? ws[addr].v : XLSX.utils.encode_col(C);
|
||||
}
|
||||
|
||||
for(var i = 0; i < names.length; ++i) if(names.indexOf(names[i]) < i)
|
||||
for(var j = 0; j < names.length; ++j) {
|
||||
var _name = names[i] + "_" + (j+1);
|
||||
if(names.indexOf(_name) > -1) continue;
|
||||
names[i] = _name;
|
||||
}
|
||||
|
||||
var types = new Array(range.e.c-range.s.c+1);
|
||||
for(C = range.s.c; C<= range.e.c; ++C) {
|
||||
var seen = {}, _type = "";
|
||||
for(R = range.s.r+1; R<= range.e.r; ++R)
|
||||
seen[(ws[XLSX.utils.encode_cell({c:C,r:R})]||{t:"z"}).t] = true;
|
||||
if(seen.s || seen.str) _type = TYPES.t;
|
||||
else if(seen.n + seen.b + seen.d + seen.e > 1) _type = TYPES.t;
|
||||
else switch(true) {
|
||||
case seen.b: _type = TYPES.b; break;
|
||||
case seen.n: _type = TYPES.n; break;
|
||||
case seen.e: _type = TYPES.t; break;
|
||||
case seen.d: _type = TYPES.d; break;
|
||||
}
|
||||
types[C-range.s.c] = _type || TYPES.t;
|
||||
}
|
||||
|
||||
await knex.schema.dropTableIfExists(n);
|
||||
await knex.schema.createTable(n, (table) => { names.forEach((n, i) => { table[types[i] || "text"](n); }); });
|
||||
|
||||
for(R = range.s.r+1; R<= range.e.r; ++R) {
|
||||
var row = {};
|
||||
for(C = range.s.c; C<= range.e.c; ++C) {
|
||||
var cell = ws[XLSX.utils.encode_cell({c:C,r:R})];
|
||||
if(!cell) continue;
|
||||
var key = names[C-range.s.c], val = cell.v;
|
||||
if(types[C-range.s.c] == TYPES.n) if(cell.t == 'b' || typeof val == 'boolean' ) val = +val;
|
||||
row[key] = val;
|
||||
}
|
||||
await knex.insert(row).into(n);;
|
||||
}
|
||||
}
|
||||
|
||||
async function wb_to_knex(wb, knex) {
|
||||
for(var i = 0; i < wb.SheetNames.length; ++i) {
|
||||
var n = wb.SheetNames[i];
|
||||
var ws = wb.Sheets[n];
|
||||
await ws_to_knex(ws, knex, n);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
book_append_knex,
|
||||
wb_to_knex
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
|
||||
var XLSX = require('xlsx');
|
||||
var ObjUtils = require('./ObjUtils');
|
||||
|
||||
function SheetJSAdapter() { this.defaultValue = {}; };
|
||||
|
||||
SheetJSAdapter.prototype.read = function() { return this.defaultValue; };
|
||||
SheetJSAdapter.prototype.write = function(/*data*/) {};
|
||||
|
||||
SheetJSAdapter.prototype.dumpRaw = function() { return ObjUtils.object_to_workbook(this.defaultValue); };
|
||||
SheetJSAdapter.prototype.dump = function(options) { XLSX.write(this.dumpRaw(), options); };
|
||||
SheetJSAdapter.prototype.dumpFile = function(path, options) { XLSX.writeFile(this.dumpRaw(), path, options); };
|
||||
|
||||
SheetJSAdapter.prototype.loadRaw = function(wb) { ObjUtils.workbook_set_object(this.defaultValue, wb); };
|
||||
SheetJSAdapter.prototype.load = function(data, options) { this.loadRaw(XLSX.read(data, options)); };
|
||||
SheetJSAdapter.prototype.loadFile = function(path, options) { this.loadRaw(XLSX.readFile(path, options)); };
|
||||
|
||||
if(typeof module !== 'undefined') module.exports = SheetJSAdapter;
|
@ -1,14 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require("xlsx");
|
||||
|
||||
async function book_append_mongo(wb, coll, name) {
|
||||
const aoo = await coll.find({}, {projection:{_id:0}}).toArray();
|
||||
const ws = XLSX.utils.json_to_sheet(aoo);
|
||||
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||
return ws;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
book_append_mongo
|
||||
};
|
@ -1,74 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
var XLSX = require("xlsx");
|
||||
|
||||
const pair = (arr) => arr.map((x,i)=>!(i%2)&&[x,+arr[i+1]]).filter(x=>x);
|
||||
const keyify = (obj) => Object.keys(obj).map(x => [x, obj[x]]);
|
||||
|
||||
async function redis_to_wb(R) {
|
||||
var wb = XLSX.utils.book_new();
|
||||
var manifest = [], strs = [];
|
||||
|
||||
/* store strings in strs and keep note of other objects in manifest */
|
||||
var keys = await R("keys")("*"), type = "";
|
||||
for(var i = 0; i < keys.length; ++i) {
|
||||
type = await R("type")(keys[i]);
|
||||
switch(type) {
|
||||
case "string": strs.push({key:keys[i], value: await R("get")(keys[i])}); break;
|
||||
case "list": case "zset": case "set": case "hash": manifest.push({key:keys[i], type:type}); break;
|
||||
default: throw new Error("bad type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/* add worksheets if relevant */
|
||||
if(strs.length > 0) {
|
||||
var wss = XLSX.utils.json_to_sheet(strs, {header: ["key", "value"], skipHeader:1});
|
||||
XLSX.utils.book_append_sheet(wb, wss, "_strs");
|
||||
}
|
||||
if(manifest.length > 0) {
|
||||
var wsm = XLSX.utils.json_to_sheet(manifest, {header: ["key", "type"]});
|
||||
XLSX.utils.book_append_sheet(wb, wsm, "_manifest");
|
||||
}
|
||||
for(i = 0; i < manifest.length; ++i) {
|
||||
var sn = "obj" + i;
|
||||
var aoa, key = manifest[i].key;
|
||||
switch((type=manifest[i].type)) {
|
||||
case "list":
|
||||
aoa = (await R("lrange")(key, 0, -1)).map(x => [x]); break;
|
||||
case "set":
|
||||
aoa = (await R("smembers")(key)).map(x => [x]); break;
|
||||
case "zset":
|
||||
aoa = pair(await R("zrange")(key, 0, -1, "withscores")); break;
|
||||
case "hash":
|
||||
aoa = keyify(await R("hgetall")(key)); break;
|
||||
default: throw new Error("bad type " + type);
|
||||
}
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(aoa), sn);
|
||||
}
|
||||
return wb;
|
||||
}
|
||||
|
||||
/* convert worksheet aoa to specific redis type */
|
||||
const aoa_to_redis = {
|
||||
list: async (aoa, R, key) => await R("RPUSH")([key].concat(aoa.map(x=>x[0]))),
|
||||
zset: async (aoa, R, key) => await R("ZADD" )([key].concat(aoa.reduce((acc,x)=>acc.concat([+x[1], x[0]]), []))),
|
||||
hash: async (aoa, R, key) => await R("HMSET")([key].concat(aoa.reduce((acc,x)=>acc.concat(x), []))),
|
||||
set: async (aoa, R, key) => await R("SADD" )([key].concat(aoa.map(x=>x[0])))
|
||||
};
|
||||
async function wb_to_redis(wb, R) {
|
||||
if(wb.Sheets._strs) {
|
||||
var strs = XLSX.utils.sheet_to_json(wb.Sheets._strs, {header:1});
|
||||
for(var i = 0; i < strs.length; ++i) await R("SET")(strs[i]);
|
||||
}
|
||||
if(!wb.Sheets._manifest) return;
|
||||
var M = XLSX.utils.sheet_to_json(wb.Sheets._manifest);
|
||||
for(i = 0; i < M.length; ++i) {
|
||||
var aoa = XLSX.utils.sheet_to_json(wb.Sheets["obj" + i], {header:1});
|
||||
await aoa_to_redis[M[i].type](aoa, R, M[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
redis_to_wb,
|
||||
wb_to_redis
|
||||
};
|
@ -1,89 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* global XLSX, require, module */
|
||||
var SheetJSSQL = (function() {
|
||||
|
||||
var X;
|
||||
if(typeof XLSX !== "undefined") X = XLSX;
|
||||
else if(typeof require !== 'undefined') X = require('xlsx');
|
||||
else throw new Error("Could not find XLSX");
|
||||
|
||||
var _TYPES = {
|
||||
"PGSQL": { t:"text", n:"float8", d:"timestamp", b:"boolean" },
|
||||
"MYSQL": { t:"TEXT", n:"REAL", d:"DATETIME", b:"TINYINT" },
|
||||
"SQLITE": { t:"TEXT", n:"REAL", d:"TEXT", b:"REAL" }
|
||||
}
|
||||
function sheet_to_sql(ws, sname, mode) {
|
||||
var TYPES = _TYPES[mode || "SQLITE"]
|
||||
if(!ws || !ws['!ref']) return;
|
||||
var range = X.utils.decode_range(ws['!ref']);
|
||||
if(!range || !range.s || !range.e || range.s > range.e) return;
|
||||
var R = range.s.r, C = range.s.c;
|
||||
|
||||
var names = new Array(range.e.c-range.s.c+1);
|
||||
for(C = range.s.c; C<= range.e.c; ++C){
|
||||
var addr = X.utils.encode_cell({c:C,r:R});
|
||||
names[C-range.s.c] = ws[addr] ? ws[addr].v : X.utils.encode_col(C);
|
||||
}
|
||||
|
||||
for(var i = 0; i < names.length; ++i) if(names.indexOf(names[i]) < i)
|
||||
for(var j = 0; j < names.length; ++j) {
|
||||
var _name = names[i] + "_" + (j+1);
|
||||
if(names.indexOf(_name) > -1) continue;
|
||||
names[i] = _name;
|
||||
}
|
||||
|
||||
var types = new Array(range.e.c-range.s.c+1);
|
||||
for(C = range.s.c; C<= range.e.c; ++C) {
|
||||
var seen = {}, _type = "";
|
||||
for(R = range.s.r+1; R<= range.e.r; ++R)
|
||||
seen[(ws[X.utils.encode_cell({c:C,r:R})]||{t:"z"}).t] = true;
|
||||
if(seen.s || seen.str) _type = TYPES.t;
|
||||
else if(seen.n + seen.b + seen.d + seen.e > 1) _type = TYPES.t;
|
||||
else switch(true) {
|
||||
case seen.b: _type = TYPES.b; break;
|
||||
case seen.n: _type = TYPES.n; break;
|
||||
case seen.e: _type = TYPES.t; break;
|
||||
case seen.d: _type = TYPES.d; break;
|
||||
}
|
||||
types[C-range.s.c] = _type || TYPES.t;
|
||||
}
|
||||
|
||||
var out = [];
|
||||
|
||||
var BT = mode == "PGSQL" ? "" : "`";
|
||||
var Q = mode == "PGSQL" ? "'" : '"';
|
||||
var J = mode == "PGSQL" ? /'/g : /"/g;
|
||||
out.push("DROP TABLE IF EXISTS " + BT + sname + BT );
|
||||
out.push("CREATE TABLE " + BT + sname + BT + " (" + names.map(function(n, i) { return BT + n + BT + " " + (types[i]||"TEXT"); }).join(", ") + ");" );
|
||||
|
||||
for(R = range.s.r+1; R<= range.e.r; ++R) {
|
||||
var fields = [], values = [];
|
||||
for(C = range.s.c; C<= range.e.c; ++C) {
|
||||
var cell = ws[X.utils.encode_cell({c:C,r:R})];
|
||||
if(!cell) continue;
|
||||
fields.push(BT + names[C-range.s.c] + BT);
|
||||
var val = cell.v;
|
||||
switch(types[C-range.s.c]) {
|
||||
case TYPES.n: if(cell.t == 'b' || typeof val == 'boolean' ) val = +val; break;
|
||||
default: val = Q + val.toString().replace(J, Q + Q) + Q;
|
||||
}
|
||||
values.push(val);
|
||||
}
|
||||
out.push("INSERT INTO " + BT +sname+ BT + " (" + fields.join(", ") + ") VALUES (" + values.join(",") + ");");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function book_to_sql(wb, mode) {
|
||||
return wb.SheetNames.reduce(function(acc, n) {
|
||||
return acc.concat(sheet_to_sql(wb.Sheets[n], n, mode));
|
||||
}, []);
|
||||
}
|
||||
|
||||
return {
|
||||
book_to_sql: book_to_sql,
|
||||
sheet_to_sql: sheet_to_sql
|
||||
};
|
||||
})();
|
||||
if(typeof module !== 'undefined') module.exports = SheetJSSQL;
|
@ -1,18 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env browser */
|
||||
/*global ObjUtils */
|
||||
Storage.prototype.load = function(data) {
|
||||
var self = this;
|
||||
Object.keys(data).forEach(function(k) {
|
||||
self.setItem(k, JSON.stringify(data[k]));
|
||||
});
|
||||
};
|
||||
|
||||
Storage.prototype.dump = function() {
|
||||
var obj = {};
|
||||
for(var i = 0; i < this.length; ++i) {
|
||||
var key = this.key(i);
|
||||
obj[key] = JSON.parse(this.getItem(key));
|
||||
}
|
||||
return ObjUtils.object_to_workbook(obj);
|
||||
};
|
1
demos/database/xlsx.full.min.js
vendored
1
demos/database/xlsx.full.min.js
vendored
@ -1 +0,0 @@
|
||||
../../dist/xlsx.full.min.js
|
@ -1,92 +1,7 @@
|
||||
# canvas-datagrid
|
||||
|
||||
The `sheet_to_json` utility function generates output arrays suitable for use
|
||||
with other JS libraries such as data grids for previewing data. After extensive
|
||||
testing, [`canvas-datagrid`](https://canvas-datagrid.js.org/demo.html) stood
|
||||
out as a very high-performance grid with an incredibly simple API.
|
||||
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/grid#canvas-datagrid)
|
||||
includes a live example and improved explanations.
|
||||
|
||||
This demo is available at <https://oss.sheetjs.com/sheetjs/datagrid.html>
|
||||
|
||||
## Obtaining the Library
|
||||
|
||||
The `canvas-datagrid` NodeJS packages include a minified script that can be
|
||||
directly inserted as a script tag. The unpkg CDN also serves this script:
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/canvas-datagrid/dist/canvas-datagrid.js"></script>
|
||||
```
|
||||
|
||||
## Previewing Data
|
||||
|
||||
The HTML document needs a container element:
|
||||
|
||||
```html
|
||||
<div id="gridctr"></div>
|
||||
```
|
||||
|
||||
Grid initialization is a one-liner:
|
||||
|
||||
```js
|
||||
var grid = canvasDatagrid({
|
||||
parentNode: document.getElementById('gridctr'),
|
||||
data: []
|
||||
});
|
||||
```
|
||||
|
||||
For large data sets, it's necessary to constrain the size of the grid.
|
||||
|
||||
```js
|
||||
grid.style.height = '100%';
|
||||
grid.style.width = '100%';
|
||||
```
|
||||
|
||||
Once the workbook is read and the worksheet is selected, assigning the data
|
||||
variable automatically updates the view:
|
||||
|
||||
```js
|
||||
grid.data = XLSX.utils.sheet_to_json(ws, {header:1});
|
||||
```
|
||||
|
||||
This demo previews the first worksheet.
|
||||
|
||||
## Editing
|
||||
|
||||
`canvas-datagrid` handles the entire edit cycle. No intervention is necessary.
|
||||
|
||||
## Saving Data
|
||||
|
||||
`grid.data` is immediately readable and can be converted back to a worksheet.
|
||||
Some versions return an array-like object without the length, so a little bit of
|
||||
preparation may be needed:
|
||||
|
||||
```js
|
||||
/* converts an array of array-like objects into an array of arrays */
|
||||
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;
|
||||
}
|
||||
|
||||
/* build worksheet from the grid data */
|
||||
var ws = XLSX.utils.aoa_to_sheet(prep(grid.data));
|
||||
|
||||
/* build up workbook */
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
|
||||
|
||||
/* generate download */
|
||||
XLSX.writeFile(wb, "SheetJS.xlsx");
|
||||
```
|
||||
|
||||
## Additional Features
|
||||
|
||||
This demo barely scratches the surface. The underlying grid component includes
|
||||
many additional features including massive data streaming, sorting and styling.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -1,162 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS + canvas-datagrid Live Demo</title>
|
||||
<style>
|
||||
#drop{
|
||||
border:2px dashed #bbb;
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
border-radius:5px;
|
||||
padding:25px;
|
||||
text-align:center;
|
||||
font:20pt bold,"Vollkorn";color:#bbb
|
||||
}
|
||||
#b64data{
|
||||
width:100%;
|
||||
}
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
|
||||
|
||||
<a href="https://canvas-datagrid.js.org/">canvas-datagrid component library</a>
|
||||
|
||||
<a href="https://github.com/SheetJS/sheetjs">Source Code Repo</a>
|
||||
<a href="https://github.com/SheetJS/sheetjs/issues">Issues? Something look weird? Click here and report an issue</a>
|
||||
|
||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
|
||||
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
|
||||
<textarea id="b64data">... or paste a base64-encoding here</textarea>
|
||||
<b>Advanced Demo Options:</b>
|
||||
</pre>
|
||||
<p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();" disabled="true"></p>
|
||||
<div id="htmlout"></div>
|
||||
<br />
|
||||
<script src="https://unpkg.com/canvas-datagrid/dist/canvas-datagrid.js"></script>
|
||||
<script src="shim.js"></script>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
<script>
|
||||
/*jshint browser:true */
|
||||
/* eslint-env browser */
|
||||
/* eslint no-use-before-define:0 */
|
||||
/*global Uint8Array, Uint16Array, ArrayBuffer */
|
||||
/*global XLSX */
|
||||
|
||||
var cDg;
|
||||
|
||||
var process_wb = (function() {
|
||||
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});
|
||||
|
||||
/* 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);
|
||||
|
||||
HTMLOUT.style.height = (window.innerHeight - 400) + "px";
|
||||
HTMLOUT.style.width = (window.innerWidth - 50) + "px";
|
||||
|
||||
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);
|
||||
};
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var drop = document.getElementById('drop');
|
||||
if(!drop.addEventListener) return;
|
||||
|
||||
function handleDrop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
do_file(e.dataTransfer.files);
|
||||
}
|
||||
|
||||
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);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
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;
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
/* write file and trigger a download */
|
||||
XLSX.writeFile(new_wb, 'sheetjs.xlsx', {bookSST:true});
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
/* eslint no-use-before-define:0 */
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
../../shim.js
|
1
demos/datagrid/xlsx.full.min.js
vendored
1
demos/datagrid/xlsx.full.min.js
vendored
@ -1 +0,0 @@
|
||||
../../dist/xlsx.full.min.js
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
},
|
||||
"plugins": [ "html", "json" ]
|
||||
}
|
1
demos/electron/.gitignore
vendored
1
demos/electron/.gitignore
vendored
@ -1 +0,0 @@
|
||||
out/
|
@ -1,7 +0,0 @@
|
||||
.PHONY: init
|
||||
init:
|
||||
if [ ! -e xlsx.full.min.js ]; then ln -s ../../dist/xlsx.full.min.js . ; fi
|
||||
|
||||
.PHONY: run
|
||||
run:
|
||||
npx nw .
|
@ -1,36 +1,6 @@
|
||||
# NW.js
|
||||
|
||||
This library is compatible with NW.js and should just work out of the box.
|
||||
The demonstration uses NW.js 0.63.0 with the dist script.
|
||||
|
||||
## Reading data
|
||||
|
||||
The standard HTML5 `FileReader` techniques from the browser apply to NW.js!
|
||||
This demo includes a drag-and-drop box as well as a file input box, mirroring
|
||||
the [SheetJS Data Preview Live Demo](https://oss.sheetjs.com/sheetjs/).
|
||||
|
||||
## Writing data
|
||||
|
||||
File input elements with the attribute `nwsaveas` show UI for saving a file. The
|
||||
standard trick is to generate a hidden file input DOM element and "click" it.
|
||||
Since NW.js does not present a `writeFileSync` in the `fs` package, a manual
|
||||
step is required:
|
||||
|
||||
```js
|
||||
/* from within the input change callback, `this.value` is the file name */
|
||||
var filename = this.value, bookType = (filename.match(/[^\.]*$/)||["xlsx"])[0];
|
||||
|
||||
/* convert the TABLE element back to a workbook */
|
||||
var wb = XLSX.utils.table_to_book(HTMLOUT);
|
||||
|
||||
/* write to buffer */
|
||||
var wbout = XLSX.write(wb, {type:'buffer', bookType:bookType});
|
||||
|
||||
/* use the async fs.writeFile to save the data */
|
||||
fs.writeFile(filename, wbout, function(err) {
|
||||
if(!err) return alert("Saved to " + filename);
|
||||
alert("Error: " + (err.message || err));
|
||||
});
|
||||
```
|
||||
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/desktop#nwjs)
|
||||
includes an improved example and detailed explanations.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS NW.js Demo</title>
|
||||
<style>
|
||||
#drop{
|
||||
border:2px dashed #bbb;
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
border-radius:5px;
|
||||
padding:25px;
|
||||
text-align:center;
|
||||
font:20pt bold,"Vollkorn";color:#bbb
|
||||
}
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS NW.js Demo</a></b>
|
||||
|
||||
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a>
|
||||
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a>
|
||||
<br />
|
||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
|
||||
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
|
||||
|
||||
</pre>
|
||||
<p><input type="submit" value="Export Data!" id="xport" onclick="export_xlsx();" disabled="true"></p>
|
||||
<div id="htmlout"></div>
|
||||
<br />
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,86 +0,0 @@
|
||||
var fs = require('fs');
|
||||
|
||||
var process_wb = (function() {
|
||||
var HTMLOUT = document.getElementById('htmlout');
|
||||
var XPORT = document.getElementById('xport');
|
||||
|
||||
return function process_wb(wb) {
|
||||
XPORT.disabled = false;
|
||||
HTMLOUT.innerHTML = "";
|
||||
wb.SheetNames.forEach(function(sheetName) {
|
||||
var htmlstr = XLSX.utils.sheet_to_html(wb.Sheets[sheetName],{editable:true});
|
||||
HTMLOUT.innerHTML += htmlstr;
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
var do_file = (function() {
|
||||
return function do_file(files) {
|
||||
var f = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
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');
|
||||
|
||||
function handleDrop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
do_file(e.dataTransfer.files);
|
||||
}
|
||||
|
||||
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);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var xlf = document.getElementById('xlf');
|
||||
function handleFile(e) { do_file(e.target.files); }
|
||||
xlf.addEventListener('change', handleFile, false);
|
||||
})();
|
||||
|
||||
var export_xlsx = (function() {
|
||||
/* pre-build the nwsaveas input element */
|
||||
var HTMLOUT = document.getElementById('htmlout');
|
||||
var input = document.createElement('input');
|
||||
input.style.display = 'none';
|
||||
input.setAttribute('nwsaveas', 'SheetJSNWDemo.xlsx');
|
||||
input.setAttribute('type', 'file');
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('cancel',function(){ alert("Save was canceled!"); });
|
||||
input.addEventListener('change',function(e){
|
||||
var filename=this.value, bookType=(filename.match(/[^\.]*$/)||["xlsx"])[0];
|
||||
var wb = XLSX.utils.table_to_book(HTMLOUT.getElementsByTagName("TABLE")[0]);
|
||||
var wbout = XLSX.write(wb, {type:'buffer', bookType:bookType});
|
||||
fs.writeFile(filename, wbout, function(err) {
|
||||
if(!err) return alert("Saved to " + filename);
|
||||
alert("Error: " + (err.message || err));
|
||||
});
|
||||
});
|
||||
|
||||
return function() { input.click(); };
|
||||
})();
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "sheetjs-nwjs",
|
||||
"author": "sheetjs",
|
||||
"version": "0.0.0",
|
||||
"main": "index.html",
|
||||
"dependencies": {
|
||||
"nw": "~0.66.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
|
||||
}
|
||||
}
|
1
demos/nwjs/xlsx.full.min.js
vendored
1
demos/nwjs/xlsx.full.min.js
vendored
@ -1 +0,0 @@
|
||||
../../dist/xlsx.full.min.js
|
3
demos/parcel/.gitignore
vendored
3
demos/parcel/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
.cache
|
||||
.parcel-cache
|
||||
dist
|
5
demos/rollup/.gitignore
vendored
5
demos/rollup/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
rollup.js
|
||||
rollup.min.js
|
||||
rollup.node.js
|
||||
worker.js
|
||||
worker.min.js
|
1
demos/typescript/.gitignore
vendored
1
demos/typescript/.gitignore
vendored
@ -1 +0,0 @@
|
||||
dist
|
@ -1,13 +0,0 @@
|
||||
.PHONY: all
|
||||
all:
|
||||
@npm run build
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@npm run lint
|
||||
|
||||
.PHONY: init
|
||||
init:
|
||||
mkdir -p node_modules
|
||||
npm install typescript
|
||||
cd node_modules; ln -s ../../../ xlsx; cd -
|
@ -1,71 +1,9 @@
|
||||
# TypeScript
|
||||
|
||||
The library exports can be imported directly from TS code with:
|
||||
|
||||
```typescript
|
||||
import * as XLSX from 'xlsx';
|
||||
```
|
||||
|
||||
The library type definitions are available in the repo at `types/index.d.ts` and
|
||||
in the node module. The definitions are also available in places that serve the
|
||||
node module, like [unpkg](https://unpkg.com/xlsx/types/index.d.ts).
|
||||
|
||||
This demo shows a small utility function that reads the first worksheet and
|
||||
converts to an array of arrays. The utility function is designed to be used in
|
||||
the browser and server. This project shows a complete deployment as a simple
|
||||
browser script and as a node module.
|
||||
|
||||
This demo is intended to illustrate simple and direct use of the `tsc` command
|
||||
line utility. The Angular 2+ demo shows a more advanced TypeScript deployment.
|
||||
|
||||
|
||||
## Named Exports
|
||||
|
||||
Newer TypeScript versions (2.6+) support named exports:
|
||||
|
||||
```typescript
|
||||
import { read, write, utils } from 'xlsx'
|
||||
```
|
||||
|
||||
However, since this is not supported in all deployments, it is generally easier
|
||||
to use the glob import form and destructuring assignment:
|
||||
|
||||
```typescript
|
||||
import * as XLSX from 'xlsx';
|
||||
const { read, write, utils } = XLSX;
|
||||
```
|
||||
|
||||
|
||||
## Library Type Definitions
|
||||
|
||||
Types are exposed in the node module directly in the path `/types/index.d.ts`.
|
||||
[unpkg CDN includes the definitions](https://unpkg.com/xlsx/types/index.d.ts).
|
||||
The named `@types/xlsx` module should not be installed!
|
||||
|
||||
Using the glob import, types must be explicitly scoped:
|
||||
|
||||
```typescript
|
||||
import * as XLSX from 'xlsx';
|
||||
/* the workbook type is accessible as XLSX.WorkBook */
|
||||
const wb: XLSX.WorkBook = XLSX.read(data, options);
|
||||
```
|
||||
|
||||
Using named imports, the explicit type name should be imported:
|
||||
|
||||
```typescript
|
||||
import { read, WorkBook } from 'xlsx'
|
||||
const wb: WorkBook = read(data, options);
|
||||
```
|
||||
|
||||
|
||||
## Demo Project Structure
|
||||
|
||||
`lib/index.ts` is the TS library that will be transpiled to `dist/index.js` and
|
||||
`dist/index.d.ts`.
|
||||
|
||||
`demo.js` is a node script that uses the generated library.
|
||||
|
||||
`src/index.js` is the browser entry point. The `browserify` bundle tool is used
|
||||
to generate `dist/browser.js`, a browser script loaded by `index.html`.
|
||||
This demo originally covered direct use of the `tsc` TypeScript compiler. At
|
||||
the time when the demo was first written, TypeScript 2.2 had a module system
|
||||
that was incompatibile with the pure JS ecosystem. Since then, various
|
||||
language improvements and compiler changes have obviated this demo. Uses of
|
||||
TypeScript are scattered throughout other demos.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -1,5 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/* eslint-env node */
|
||||
var readFirstSheet = require("./").readFirstSheet;
|
||||
console.log(readFirstSheet("../../sheetjs.xlsb", {type:"file", cellDates:true}));
|
@ -1 +0,0 @@
|
||||
<script src="dist/browser.js"></script>
|
@ -1,12 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
const { read, utils: { sheet_to_json } } = XLSX;
|
||||
|
||||
export function readFirstSheet(data: any, options: XLSX.ParsingOptions): any[][] {
|
||||
const wb: XLSX.WorkBook = read(data, options);
|
||||
const ws: XLSX.WorkSheet = wb.Sheets[wb.SheetNames[0]];
|
||||
return sheet_to_json(ws, { header: 1, raw: true });
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "xlsx-ts",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "tsc && browserify -o dist/browser.js src/index.js",
|
||||
"lint": "tslint lib/*.ts"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~2.6.1",
|
||||
"browserify": "~14.5.0"
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/* eslint-env browser */
|
||||
/* global require */
|
||||
var readFirstSheet = require("../").readFirstSheet;
|
||||
console.log(readFirstSheet("a,b,c\n1,2,3\n4,5,6", {type:"binary"}));
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"strict": true
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "tslint-config-airbnb",
|
||||
"rules": {
|
||||
"whitespace": false,
|
||||
"no-sparse-arrays": false,
|
||||
"only-arrow-functions": false,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"prefer-conditional-expression": false,
|
||||
"one-variable-per-declaration": false
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ function stox(wb) {
|
||||
wb.SheetNames.forEach(function (name) {
|
||||
var o = { name: name, rows: {} };
|
||||
var ws = wb.Sheets[name];
|
||||
if(!ws || !ws["!ref"]) return;
|
||||
var range = XLSX.utils.decode_range(ws['!ref']);
|
||||
// sheet_to_json will lost empty row and col at begin as default
|
||||
range.s = { r: 0, c: 0 };
|
||||
|
Loading…
Reference in New Issue
Block a user