stox skip blank worksheets [ci skip]

This commit is contained in:
SheetJS 2022-08-03 12:37:10 -04:00
parent d55b7a3063
commit c02eb14255
68 changed files with 29 additions and 2720 deletions

@ -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)

@ -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

@ -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 +0,0 @@
../../shim.js

@ -1 +0,0 @@
../../dist/xlsx.core.min.js

@ -1 +0,0 @@
../../dist/xlsx.full.min.js

@ -1,4 +0,0 @@
browserify.js
browserify.min.js
worker.js
worker.min.js

@ -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 +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 +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 +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 +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 +0,0 @@
../../dist/xlsx.full.min.js

@ -1,3 +0,0 @@
.cache
.parcel-cache
dist

@ -1,5 +0,0 @@
rollup.js
rollup.min.js
rollup.node.js
worker.js
worker.min.js

@ -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 };