diff --git a/demos/README.md b/demos/README.md index d2786b5..7539740 100644 --- a/demos/README.md +++ b/demos/README.md @@ -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) diff --git a/demos/angular/README.md b/demos/angular/README.md index 4aa1b7e..44c77ad 100644 --- a/demos/angular/README.md +++ b/demos/angular/README.md @@ -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 - -``` - -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 - - - - - - -
NameIndex
{{row.Name}}{{row.Index}}
-``` - -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 - -``` - -- 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) diff --git a/demos/angular/SheetJS-angular.js b/demos/angular/SheetJS-angular.js deleted file mode 100644 index 7175397..0000000 --- a/demos/angular/SheetJS-angular.js +++ /dev/null @@ -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]); - }); - } - }; -} diff --git a/demos/angular/app.js b/demos/angular/app.js deleted file mode 100644 index e71205f..0000000 --- a/demos/angular/app.js +++ /dev/null @@ -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]); diff --git a/demos/angular/grid.html b/demos/angular/grid.html deleted file mode 100644 index 3f8687f..0000000 --- a/demos/angular/grid.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - SheetJS + AngularJS + ui-grid - - - - - - - - - - - - - - - - - - - -
-SheetJS + AngularJS demo
-
-The core library can be used as-is in AngularJS applications.
-The Community Edition README details some common use cases.
-We also have some more public demos
-
-This demo shows:
-- SheetJSExportService: a service for exporting data from a ui-grid
-- SheetJSImportDirective: a directive providing a file input button for import
-
-Sample Spreadsheet
-
- -
- -
-
- - - - - diff --git a/demos/angular/index.html b/demos/angular/index.html deleted file mode 100644 index b06978a..0000000 --- a/demos/angular/index.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - SheetJS + AngularJS - - - - - - - - -
-SheetJS + AngularJS demo
-
-The core library can be used as-is in AngularJS applications.
-The Community Edition README details some common use cases.
-We also have some more public demos
-
-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`
-
-Sample Spreadsheet
-
- -
- - - - - - - -
NameIndex
{{row.Name}}{{row.Index}}
- - - -
- - - - - diff --git a/demos/angular/shim.js b/demos/angular/shim.js deleted file mode 120000 index 7ec5819..0000000 --- a/demos/angular/shim.js +++ /dev/null @@ -1 +0,0 @@ -../../shim.js \ No newline at end of file diff --git a/demos/angular/xlsx.core.min.js b/demos/angular/xlsx.core.min.js deleted file mode 120000 index 383ccb8..0000000 --- a/demos/angular/xlsx.core.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.core.min.js \ No newline at end of file diff --git a/demos/angular/xlsx.full.min.js b/demos/angular/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/angular/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/demos/browserify/.gitignore b/demos/browserify/.gitignore deleted file mode 100644 index 9db8fdf..0000000 --- a/demos/browserify/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -browserify.js -browserify.min.js -worker.js -worker.min.js diff --git a/demos/chrome/.gitignore b/demos/chrome/.gitignore deleted file mode 100644 index fd59484..0000000 --- a/demos/chrome/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -xlsx.*.js -logo.png diff --git a/demos/chrome/Makefile b/demos/chrome/Makefile deleted file mode 100644 index d708d07..0000000 --- a/demos/chrome/Makefile +++ /dev/null @@ -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 diff --git a/demos/chrome/README.md b/demos/chrome/README.md index cf75b2f..799ad17 100644 --- a/demos/chrome/README.md +++ b/demos/chrome/README.md @@ -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) diff --git a/demos/chrome/content.js b/demos/chrome/content.js deleted file mode 100644 index 493614e..0000000 --- a/demos/chrome/content.js +++ /dev/null @@ -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); -}); diff --git a/demos/chrome/manifest.json b/demos/chrome/manifest.json deleted file mode 100644 index 8aa8fd0..0000000 --- a/demos/chrome/manifest.json +++ /dev/null @@ -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": [""], - "js": ["content.js", "xlsx.full.min.js"], - "run_at": "document_end" - }], - "icons": { - "16": "logo.png" - }, - "permissions": [ - "activeTab", - "", - "bookmarks", - "contextMenus", - "downloads", - "tabs" - ] -} diff --git a/demos/chrome/popup.html b/demos/chrome/popup.html deleted file mode 100644 index d4b7139..0000000 --- a/demos/chrome/popup.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -SheetJS Chrome Extension Export Test - - - - - - - -
Version
- - - - \ No newline at end of file diff --git a/demos/chrome/popup.js b/demos/chrome/popup.js deleted file mode 100644 index b83e7fd..0000000 --- a/demos/chrome/popup.js +++ /dev/null @@ -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"); - }); -}); diff --git a/demos/chrome/table.js b/demos/chrome/table.js deleted file mode 100644 index 732aefd..0000000 --- a/demos/chrome/table.js +++ /dev/null @@ -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"); -} diff --git a/demos/database/.eslintrc b/demos/database/.eslintrc deleted file mode 100644 index dbf6551..0000000 --- a/demos/database/.eslintrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "env": { "shared-node-browser":true }, - "parserOptions": { - "ecmaVersion": 8 - }, - "plugins": [ "html", "json" ] -} diff --git a/demos/database/.gitignore b/demos/database/.gitignore deleted file mode 100644 index 98e6ef6..0000000 --- a/demos/database/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.db diff --git a/demos/database/FirebaseDemo.html b/demos/database/FirebaseDemo.html deleted file mode 100644 index c66470b..0000000 --- a/demos/database/FirebaseDemo.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - -SheetJS Firebase Dump Demo - - - -
-

SheetJS Firebase Dump Demo

-Example Code - - /* ... 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"); - -
- - - - diff --git a/demos/database/FirebaseTest.js b/demos/database/FirebaseTest.js deleted file mode 100644 index 737c2a7..0000000 --- a/demos/database/FirebaseTest.js +++ /dev/null @@ -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(); }); diff --git a/demos/database/KnexTest.js b/demos/database/KnexTest.js deleted file mode 100644 index 9675da2..0000000 --- a/demos/database/KnexTest.js +++ /dev/null @@ -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(); }); diff --git a/demos/database/LocalForage.html b/demos/database/LocalForage.html deleted file mode 100644 index 6534702..0000000 --- a/demos/database/LocalForage.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - -SheetJS Live Demo - - - -
-SheetJS LocalStorage Demo
-
-Original Data:
-
-
-Output:
-
-
- - - - - - - diff --git a/demos/database/LocalStorage.html b/demos/database/LocalStorage.html deleted file mode 100644 index 780184d..0000000 --- a/demos/database/LocalStorage.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - -SheetJS Live Demo - - - -
-SheetJS LocalStorage Demo
-
-Original Data:
-
-
-Output:
-
-
- - - - - - diff --git a/demos/database/LowDBTest.js b/demos/database/LowDBTest.js deleted file mode 100644 index baa8c4f..0000000 --- a/demos/database/LowDBTest.js +++ /dev/null @@ -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'); diff --git a/demos/database/Makefile b/demos/database/Makefile deleted file mode 100644 index f0418d1..0000000 --- a/demos/database/Makefile +++ /dev/null @@ -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 diff --git a/demos/database/MongoDBCRUD.js b/demos/database/MongoDBCRUD.js deleted file mode 100644 index 495da6d..0000000 --- a/demos/database/MongoDBCRUD.js +++ /dev/null @@ -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(); }); \ No newline at end of file diff --git a/demos/database/MongoDBTest.js b/demos/database/MongoDBTest.js deleted file mode 100644 index fa360ca..0000000 --- a/demos/database/MongoDBTest.js +++ /dev/null @@ -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(); }); diff --git a/demos/database/MySQLTest.js b/demos/database/MySQLTest.js deleted file mode 100644 index 43ea452..0000000 --- a/demos/database/MySQLTest.js +++ /dev/null @@ -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); -})(); diff --git a/demos/database/ObjUtils.js b/demos/database/ObjUtils.js deleted file mode 100644 index cb3a0c5..0000000 --- a/demos/database/ObjUtils.js +++ /dev/null @@ -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; diff --git a/demos/database/PgSQLTest.js b/demos/database/PgSQLTest.js deleted file mode 100644 index b1d6651..0000000 --- a/demos/database/PgSQLTest.js +++ /dev/null @@ -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); -})(); diff --git a/demos/database/README.md b/demos/database/README.md index 901722d..9117f85 100644 --- a/demos/database/README.md +++ b/demos/database/README.md @@ -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. +- 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. - -
- Implementation details (click to show) - -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"; - } -``` - -
- -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: - -
- Implementation details (click to show) - -```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; -} -``` - -
- - -## 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 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: - -
- Example code (click to show) - -```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}); -``` - -
- -#### 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) diff --git a/demos/database/RedisTest.js b/demos/database/RedisTest.js deleted file mode 100644 index e5c7c18..0000000 --- a/demos/database/RedisTest.js +++ /dev/null @@ -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(); -})(); diff --git a/demos/database/SQLiteTest.js b/demos/database/SQLiteTest.js deleted file mode 100644 index fb21812..0000000 --- a/demos/database/SQLiteTest.js +++ /dev/null @@ -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); - diff --git a/demos/database/SheetJSForage.js b/demos/database/SheetJSForage.js deleted file mode 100644 index 39b0a65..0000000 --- a/demos/database/SheetJSForage.js +++ /dev/null @@ -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); -}; diff --git a/demos/database/SheetJSKnex.js b/demos/database/SheetJSKnex.js deleted file mode 100644 index d9b1758..0000000 --- a/demos/database/SheetJSKnex.js +++ /dev/null @@ -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 -}; diff --git a/demos/database/SheetJSLowDB.js b/demos/database/SheetJSLowDB.js deleted file mode 100644 index 0c7906f..0000000 --- a/demos/database/SheetJSLowDB.js +++ /dev/null @@ -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; diff --git a/demos/database/SheetJSMongo.js b/demos/database/SheetJSMongo.js deleted file mode 100644 index 08f6e29..0000000 --- a/demos/database/SheetJSMongo.js +++ /dev/null @@ -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 -}; \ No newline at end of file diff --git a/demos/database/SheetJSRedis.js b/demos/database/SheetJSRedis.js deleted file mode 100644 index 1231ebf..0000000 --- a/demos/database/SheetJSRedis.js +++ /dev/null @@ -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 -}; diff --git a/demos/database/SheetJSSQL.js b/demos/database/SheetJSSQL.js deleted file mode 100644 index 731d3b1..0000000 --- a/demos/database/SheetJSSQL.js +++ /dev/null @@ -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; diff --git a/demos/database/SheetJSStorage.js b/demos/database/SheetJSStorage.js deleted file mode 100644 index 3e5eac4..0000000 --- a/demos/database/SheetJSStorage.js +++ /dev/null @@ -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); -}; diff --git a/demos/database/xlsx.full.min.js b/demos/database/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/database/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/demos/datagrid/README.md b/demos/datagrid/README.md index f367779..cac7ca3 100644 --- a/demos/datagrid/README.md +++ b/demos/datagrid/README.md @@ -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 - -## 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 - -``` - -## Previewing Data - -The HTML document needs a container element: - -```html -
-``` - -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) diff --git a/demos/datagrid/index.html b/demos/datagrid/index.html deleted file mode 100644 index 1cf7e5f..0000000 --- a/demos/datagrid/index.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - -SheetJS + canvas-datagrid Live Demo - - - -
-SheetJS Data Preview Live Demo
-
-canvas-datagrid component library
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
Drop a spreadsheet file here to see sheet data
- ... or click here to select a file - -Advanced Demo Options: -
-

-
-
- - - - - - - diff --git a/demos/datagrid/shim.js b/demos/datagrid/shim.js deleted file mode 120000 index 7ec5819..0000000 --- a/demos/datagrid/shim.js +++ /dev/null @@ -1 +0,0 @@ -../../shim.js \ No newline at end of file diff --git a/demos/datagrid/xlsx.full.min.js b/demos/datagrid/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/datagrid/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/demos/electron/.eslintrc b/demos/electron/.eslintrc deleted file mode 100644 index dd47106..0000000 --- a/demos/electron/.eslintrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "env": { - "es6": true, - "browser": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": 8 - }, - "plugins": [ "html", "json" ] -} diff --git a/demos/electron/.gitignore b/demos/electron/.gitignore deleted file mode 100644 index 89f9ac0..0000000 --- a/demos/electron/.gitignore +++ /dev/null @@ -1 +0,0 @@ -out/ diff --git a/demos/nwjs/Makefile b/demos/nwjs/Makefile deleted file mode 100644 index 70dec6a..0000000 --- a/demos/nwjs/Makefile +++ /dev/null @@ -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 . diff --git a/demos/nwjs/README.md b/demos/nwjs/README.md index e08ed48..14c1361 100644 --- a/demos/nwjs/README.md +++ b/demos/nwjs/README.md @@ -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) diff --git a/demos/nwjs/index.html b/demos/nwjs/index.html deleted file mode 100644 index fc61e75..0000000 --- a/demos/nwjs/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - -SheetJS NW.js Demo - - - -
-SheetJS NW.js Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
Drop a spreadsheet file here to see sheet data
- ... or click here to select a file - -
-

-
-
- - - - diff --git a/demos/nwjs/index.js b/demos/nwjs/index.js deleted file mode 100644 index fc95ca3..0000000 --- a/demos/nwjs/index.js +++ /dev/null @@ -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(); }; -})(); diff --git a/demos/nwjs/package.json b/demos/nwjs/package.json deleted file mode 100644 index a36ec40..0000000 --- a/demos/nwjs/package.json +++ /dev/null @@ -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" - } -} diff --git a/demos/nwjs/xlsx.full.min.js b/demos/nwjs/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/nwjs/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/demos/parcel/.gitignore b/demos/parcel/.gitignore deleted file mode 100644 index 55f055f..0000000 --- a/demos/parcel/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.cache -.parcel-cache -dist diff --git a/demos/rollup/.gitignore b/demos/rollup/.gitignore deleted file mode 100644 index 0c7a847..0000000 --- a/demos/rollup/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -rollup.js -rollup.min.js -rollup.node.js -worker.js -worker.min.js diff --git a/demos/typescript/.gitignore b/demos/typescript/.gitignore deleted file mode 100644 index 1521c8b..0000000 --- a/demos/typescript/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/demos/typescript/Makefile b/demos/typescript/Makefile deleted file mode 100644 index 3e9b2e7..0000000 --- a/demos/typescript/Makefile +++ /dev/null @@ -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 - diff --git a/demos/typescript/README.md b/demos/typescript/README.md index 6c4f1a1..c345d86 100644 --- a/demos/typescript/README.md +++ b/demos/typescript/README.md @@ -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) diff --git a/demos/typescript/demo.js b/demos/typescript/demo.js deleted file mode 100644 index 15ad0e4..0000000 --- a/demos/typescript/demo.js +++ /dev/null @@ -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})); \ No newline at end of file diff --git a/demos/typescript/index.html b/demos/typescript/index.html deleted file mode 100644 index 20b9432..0000000 --- a/demos/typescript/index.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/demos/typescript/lib/index.ts b/demos/typescript/lib/index.ts deleted file mode 100644 index 9efda61..0000000 --- a/demos/typescript/lib/index.ts +++ /dev/null @@ -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 }); -} diff --git a/demos/typescript/package.json b/demos/typescript/package.json deleted file mode 100644 index b76dd65..0000000 --- a/demos/typescript/package.json +++ /dev/null @@ -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" - } -} diff --git a/demos/typescript/src/index.js b/demos/typescript/src/index.js deleted file mode 100644 index f45d8c0..0000000 --- a/demos/typescript/src/index.js +++ /dev/null @@ -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"})); \ No newline at end of file diff --git a/demos/typescript/tsconfig.json b/demos/typescript/tsconfig.json deleted file mode 100644 index 6ac3891..0000000 --- a/demos/typescript/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "declaration": true, - "outDir": "./dist", - "strict": true - } -} \ No newline at end of file diff --git a/demos/typescript/tslint.json b/demos/typescript/tslint.json deleted file mode 100644 index d024382..0000000 --- a/demos/typescript/tslint.json +++ /dev/null @@ -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 - } -} diff --git a/demos/xspreadsheet/xlsxspread.js b/demos/xspreadsheet/xlsxspread.js index 13e44d4..d4b88f9 100644 --- a/demos/xspreadsheet/xlsxspread.js +++ b/demos/xspreadsheet/xlsxspread.js @@ -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 };