-
-
Save DenL/bd25448d90b84e5b7792 to your computer and use it in GitHub Desktop.
Google Spreadsheet JSON ExportHow-to at http://blog.pamelafox.org/2013/06/exporting-google-spreadsheet-as-json.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Includes functions for exporting active sheet or all sheets as JSON object (also Python object syntax compatible). | |
// Tweak the makePrettyJSON_ function to customize what kind of JSON to export. | |
// ignore row/column if first row/column contains this key | |
var IGNORE_KEYS = ["ignore", "void"]; | |
var EXPORT_FOLDER = "JsonExport"; | |
var EXPORT_TYPE_JSON = "Json"; | |
var EXPORT_TYPE_CSV = "Csv"; | |
var FUNCTION_EXPORT_JSON = "exportJson"; | |
var FUNCTION_EXPORT_CSV = "exportCsv"; | |
function onOpen() { | |
var ui = SpreadsheetApp.getUi(); | |
ui.createMenu('Export') | |
.addItem('Preview Json', 'previewJson') | |
.addItem('Export Json', FUNCTION_EXPORT_JSON) | |
.addItem('Export Csv', FUNCTION_EXPORT_CSV) | |
.addItem('Options...', 'optionsDialog') | |
.addToUi(); | |
} | |
function optionsDialog() { | |
var htmlOutput = HtmlService | |
.createTemplateFromFile('options') | |
.evaluate() | |
.setWidth(250) | |
.setHeight(150); | |
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Options'); | |
} | |
function saveOptions(options) { | |
var ui = SpreadsheetApp.getUi(); | |
//ui.alert(JSON.stringify(options)); | |
if (!options.hasOwnProperty('exportKeyed')) | |
options.exportKeyed = false; | |
if (!options.hasOwnProperty('stopOnBlank')) | |
options.stopOnBlank = false; | |
if (!options.hasOwnProperty('encrypt')) | |
options.encrypt = false; | |
var properties = PropertiesService.getUserProperties(); | |
properties.setProperty('options', JSON.stringify(options)); | |
} | |
function getOptions() { | |
var properties = PropertiesService.getUserProperties(); | |
var options = JSON.parse(properties.getProperty('options')); | |
if (options == null) | |
options = {}; | |
if (!options.hasOwnProperty('exportKeyed')) | |
options.exportKeyed = false; | |
if (!options.hasOwnProperty('stopOnBlank')) | |
options.stopOnBlank = true; | |
if (!options.hasOwnProperty('encrypt')) | |
options.encrypt = true; | |
return options; | |
} | |
function previewJson(e) { | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = ss.getActiveSheet(); | |
var options = getOptions(); | |
options.exportType = EXPORT_TYPE_JSON; | |
var rowsData = getRowsData_(sheet, options); | |
var json = JSON.stringify(rowsData, parseArray, 4); | |
return showPreview(json); | |
} | |
function showPreview(text) { | |
var ui = SpreadsheetApp.getUi(); | |
ui.alert(text); | |
} | |
function exportJson(e) { | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = ss.getActiveSheet(); | |
var options = getOptions(); | |
options.exportType = EXPORT_TYPE_JSON; | |
var rowsData = getRowsData_(sheet, options); | |
var json = JSON.stringify(rowsData, parseArray); | |
var fileName = sheet.getName(); | |
// if set to encrypt | |
if (options.encrypt) { | |
json = EncryptDecrypt(json); | |
fileName += ".bytes"; | |
} | |
else | |
fileName += ".json"; | |
exportData(json, ss, fileName); | |
} | |
function exportCsv(e) { | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = ss.getActiveSheet(); | |
var options = getOptions(); | |
options.exportType = EXPORT_TYPE_CSV; | |
var rowsData = getRowsData_(sheet, options); | |
// start convert to csv | |
var csv = ""; | |
// loop through the data in the range and build a string with the csv data | |
if (rowsData.length > 1) { | |
for (var row = 0; row < rowsData.length; row++) { | |
for (var col = 0; col < rowsData[row].length; col++) { | |
// if has a quote use double quotes instead | |
rowsData[row][col] = rowsData[row][col].toString().replace(/\"/g, "\"\""); | |
// if cell data has comma, newline, or quotes need to surround it with quotes | |
if (rowsData[row][col].toString().indexOf(",") != -1 || rowsData[row][col].toString().indexOf("\n") != -1 || rowsData[row][col].toString().indexOf("\"\"") != -1) { | |
rowsData[row][col] = "\"" + rowsData[row][col] + "\""; | |
} | |
} | |
// join each row's columns | |
if (row < rowsData.length-1) { | |
csv += rowsData[row].join(",") + "\r\n"; | |
} | |
// last row has no carriage return | |
else { | |
csv += rowsData[row]; | |
} | |
} | |
} | |
var fileName = sheet.getName(); | |
// if set to encrypt | |
if (options.encrypt) { | |
csv = EncryptDecrypt(csv); | |
fileName += ".bytes"; | |
} | |
else | |
fileName += ".csv"; | |
exportData(csv, ss, fileName); | |
} | |
function exportData(data, ss, fileName) { | |
// get folder to export to | |
var currentFolder = DriveApp.getFileById(ss.getId()).getParents(); | |
if (currentFolder.hasNext()) | |
currentFolder = currentFolder.next(); | |
else | |
currentFolder = DriveApp.getRootFolder(); | |
var exportFolder = currentFolder.getFoldersByName(EXPORT_FOLDER); | |
if (exportFolder.hasNext()) | |
exportFolder = exportFolder.next(); | |
else | |
exportFolder = currentFolder.createFolder(EXPORT_FOLDER); | |
// delete existing file | |
/* Hash file name | |
var fileName = Utilities.base64Encode(Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, sheet.getName())) + ".bytes"; | |
Logger.log(Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, sheet.getName()).reduce(function(str,chr) { | |
chr = (chr < 0 ? chr + 256 : chr).toString(16); | |
return str + (chr.length==1?'0':'') + chr; | |
},'')); | |
*/ | |
var existingFiles = exportFolder.getFilesByName(fileName); | |
while (existingFiles.hasNext()) { | |
existingFiles.next().setTrashed(true); | |
} | |
var file = exportFolder.createFile(fileName, data); | |
showURL(file.getUrl()); | |
} | |
function parseArray(key, value) { | |
if (value && typeof key == "string" && key.indexOf('[]') > -1) { | |
var splitStr = value.split(','); | |
var isNumber = true; | |
var splitNum = []; | |
for (var i=0; i<splitStr.length; i++) { | |
isNumber = isNumber && !isNaN(splitStr[i]); | |
if (isNumber) | |
splitNum.push(+splitStr[i]); | |
else | |
break; | |
} | |
if (isNumber) | |
return splitNum; | |
else | |
return splitStr; | |
} | |
else | |
return value; | |
} | |
function EncryptDecrypt(value) { | |
var key = SpreadsheetApp.getActiveSpreadsheet().getRange("Warning!D31").getValue(); | |
var keyLength = key.length; | |
var str = []; | |
for (var i=0; i<value.length; i++) { | |
str[i] = String.fromCharCode(value.charCodeAt(i) ^ key.charCodeAt(i%keyLength)) | |
} | |
return str.join(''); | |
} | |
function showURL(href){ | |
var htmlOutput = HtmlService | |
.createHtmlOutput('<a href="'+href+'" target="_top" download>Download</a>') | |
.setWidth(200) | |
.setHeight(50); | |
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'File Generated'); | |
} | |
// getRowsData iterates row by row in the input range and returns an array of objects. | |
// Each object contains all the data for a given row, indexed by its normalized column name. | |
// Returns an Array of objects. | |
function getRowsData_(sheet, options) { | |
// Get frozen rows or just the top row | |
var headerRows = Math.max(1, sheet.getFrozenRows()); | |
var headersRange = sheet.getRange(1, 1, headerRows, sheet.getMaxColumns()); | |
var headers = headersRange.getValues()[0]; | |
var dataRange = sheet.getRange(headerRows+1, 1, sheet.getMaxRows(), sheet.getMaxColumns()); | |
var objects = getObjects_(dataRange.getValues(), headers, options); | |
return objects; | |
} | |
// For every row of data in data, generates an object that contains the data. Names of | |
// object fields are defined in keys. | |
// Arguments: | |
// - data: JavaScript 2d array | |
// - keys: Array of Strings that define the property names for the objects to create | |
function getObjects_(data, keys, options) { | |
var objectDicts = []; | |
var objectLists = []; | |
var keyedObjects = {}; | |
for (var i = 0; i < data.length; ++i) { | |
var objectDict = {}; | |
var objectList = []; | |
// skip or stop when encounter blank row key | |
if (isCellEmpty_(data[i][0])) { | |
if (options.stopOnBlank) | |
break; | |
else | |
continue; | |
} | |
// check to ignore row | |
if (IGNORE_KEYS.indexOf(data[i][0]) > -1) { | |
continue; | |
} | |
var hasData = false; | |
for (var j = 0; j < data[i].length; ++j) { | |
// stop when encounter blank column key | |
if (isCellEmpty_(keys[j])) { | |
if (options.stopOnBlank) | |
break; | |
else | |
continue; | |
} | |
// check to ignore column | |
if (IGNORE_KEYS.indexOf(keys[j]) > -1) { | |
continue; | |
} | |
var cellData = data[i][j]; | |
objectDict[keys[j]] = cellData; | |
objectList.push(cellData); | |
hasData = true; | |
} | |
if (hasData) { | |
objectDicts.push(objectDict); | |
keyedObjects[data[i][0]] = objectDict; | |
objectLists.push(objectList); | |
} | |
} | |
if (options.exportType == EXPORT_TYPE_JSON) { | |
if (options.exportKeyed) | |
return keyedObjects; | |
else | |
return objectDicts; | |
} | |
else if (options.exportType == EXPORT_TYPE_CSV) { | |
// need to add the keyrow to first row of csv | |
var allKeys = []; | |
for (var i=0; i < keys.length; i++) { | |
if (IGNORE_KEYS.indexOf(keys[i]) > -1) { | |
continue; | |
} | |
if (isCellEmpty_(keys[i])) { | |
if (options.stopOnBlank) | |
break; | |
else | |
continue; | |
} | |
allKeys.push(keys[i]); | |
} | |
objectLists.splice(0, 0, allKeys); | |
return objectLists; | |
} | |
} | |
// Returns true if the cell where cellData was read from is empty. | |
// Arguments: | |
// - cellData: string | |
function isCellEmpty_(cellData) { | |
return typeof(cellData) == 'string' && cellData == ""; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<base target="_top"> | |
</head> | |
<body> | |
<? var options = getOptions(); ?> | |
<form onsubmit="event.preventDefault(); google.script.run.saveOptions(this)"> | |
<input name="exportKeyed" type="checkbox" value="true" <? if (options.exportKeyed) { ?>checked<? } ?>/> Export Keyed<br /> | |
<input name="stopOnBlank" type="checkbox" value="true" <? if (options.stopOnBlank) { ?>checked<? } ?>/> Stop on Blank<br /> | |
<input name="encrypt" type="checkbox" value="true" <? if (options.encrypt) { ?>checked<? } ?>/> Encrypt Output<br /> <br/> | |
<button type="submit" value="Submit">Save</button> | |
</form> | |
</body> | |
</html> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment