Advertisement
Guest User

Untitled

a guest
Feb 24th, 2017
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.60 KB | None | 0 0
  1. // Includes functions for exporting active sheet or all sheets as JSON object (also Python object syntax compatible).
  2. // Tweak the makePrettyJSON_ function to customize what kind of JSON to export.
  3.  
  4. var FORMAT_ONELINE = 'One-line';
  5. var FORMAT_MULTILINE = 'Multi-line';
  6. var FORMAT_PRETTY = 'Pretty';
  7.  
  8. var LANGUAGE_JS = 'JavaScript';
  9. var LANGUAGE_PYTHON = 'Python';
  10.  
  11. var STRUCTURE_LIST = 'List';
  12. var STRUCTURE_HASH = 'Hash (keyed by "id" column)';
  13.  
  14. /* Defaults for this particular spreadsheet, change as desired */
  15. var DEFAULT_FORMAT = FORMAT_PRETTY;
  16. var DEFAULT_LANGUAGE = LANGUAGE_JS;
  17. var DEFAULT_STRUCTURE = STRUCTURE_LIST;
  18. var DEFUALT_NORMALIZE = true;
  19.  
  20. function onOpen() {
  21. var ss = SpreadsheetApp.getActiveSpreadsheet();
  22. var menuEntries = [
  23. {name: "Export JSON for this sheet", functionName: "exportSheet"},
  24. {name: "Export JSON for all sheets", functionName: "exportAllSheets"},
  25. {name: "Configure export", functionName: "exportOptions"},
  26. ];
  27. ss.addMenu("Export JSON", menuEntries);
  28. }
  29.  
  30.  
  31. function exportOptions() {
  32. var doc = SpreadsheetApp.getActiveSpreadsheet();
  33. var app = UiApp.createApplication().setTitle('Export JSON');
  34.  
  35. var grid = app.createGrid(5, 2);
  36. grid.setWidget(0, 0, makeLabel(app, 'Language:'));
  37. grid.setWidget(0, 1, makeListBox(app, 'language', [LANGUAGE_JS, LANGUAGE_PYTHON]));
  38. grid.setWidget(1, 0, makeLabel(app, 'Format:'));
  39. grid.setWidget(1, 1, makeListBox(app, 'format', [FORMAT_PRETTY, FORMAT_MULTILINE, FORMAT_ONELINE]));
  40. grid.setWidget(2, 0, makeLabel(app, 'Structure:'));
  41. grid.setWidget(2, 1, makeListBox(app, 'structure', [STRUCTURE_LIST, STRUCTURE_HASH]));
  42. grid.setWidget(3, 0, makeLabel(app, 'Normalize Headers:'));
  43. grid.setWidget(3, 1, makeCheckBox(app, 'normalize'));
  44. grid.setWidget(4, 0, makeButton(app, grid, 'Export Active Sheet', 'exportSheet'));
  45. grid.setWidget(4, 1, makeButton(app, grid, 'Export All Sheets', 'exportAllSheets'));
  46. app.add(grid);
  47.  
  48. doc.show(app);
  49. }
  50.  
  51. function makeLabel(app, text, id) {
  52. var lb = app.createLabel(text);
  53. if (id) lb.setId(id);
  54. return lb;
  55. }
  56.  
  57. function makeListBox(app, name, items) {
  58. var listBox = app.createListBox().setId(name).setName(name);
  59. listBox.setVisibleItemCount(1);
  60.  
  61. var cache = CacheService.getPublicCache();
  62. var selectedValue = cache.get(name);
  63. Logger.log(selectedValue);
  64. for (var i = 0; i < items.length; i++) {
  65. listBox.addItem(items[i]);
  66. if (items[1] == selectedValue) {
  67. listBox.setSelectedIndex(i);
  68. }
  69. }
  70. return listBox;
  71. }
  72.  
  73. function makeButton(app, parent, name, callback) {
  74. var button = app.createButton(name);
  75. app.add(button);
  76. var handler = app.createServerClickHandler(callback).addCallbackElement(parent);;
  77. button.addClickHandler(handler);
  78. return button;
  79. }
  80.  
  81. function makeTextBox(app, name) {
  82. var textArea = app.createTextArea().setWidth('100%').setHeight('200px').setId(name).setName(name);
  83. return textArea;
  84. }
  85.  
  86. function makeCheckBox(app, name) {
  87. var checkBox = app.createCheckBox().setId(name).setName(name);
  88.  
  89. var cache = CacheService.getPublicCache();
  90. var selectedValue = (cache.get(name) === 'true');
  91. Logger.log(selectedValue);
  92. checkBox.setValue(selectedValue);
  93.  
  94. return checkBox
  95. }
  96.  
  97. function exportAllSheets(e) {
  98.  
  99. var ss = SpreadsheetApp.getActiveSpreadsheet();
  100. var sheets = ss.getSheets();
  101. var sheetsData = {};
  102. for (var i = 0; i < sheets.length; i++) {
  103. var sheet = sheets[i];
  104. var rowsData = getRowsData_(sheet, getExportOptions(e));
  105. var sheetName = sheet.getName();
  106. sheetsData[sheetName] = rowsData;
  107. }
  108. var json = makeJSON_(sheetsData, getExportOptions(e));
  109. return displayText_(json);
  110. }
  111.  
  112. function exportSheet(e) {
  113. var ss = SpreadsheetApp.getActiveSpreadsheet();
  114. var sheet = ss.getActiveSheet();
  115. var rowsData = getRowsData_(sheet, getExportOptions(e));
  116. var json = makeJSON_(rowsData, getExportOptions(e));
  117. return displayText_(json);
  118. }
  119.  
  120. function getExportOptions(e) {
  121. var options = {};
  122.  
  123. options.language = e && e.parameter.language || DEFAULT_LANGUAGE;
  124. options.format = e && e.parameter.format || DEFAULT_FORMAT;
  125. options.structure = e && e.parameter.structure || DEFAULT_STRUCTURE;
  126. options.normalize = e && e.parameter.normalize || DEFUALT_NORMALIZE;
  127.  
  128. var cache = CacheService.getPublicCache();
  129. cache.put('language', options.language);
  130. cache.put('format', options.format);
  131. cache.put('structure', options.structure);
  132. cache.put('normalize', options.normalize);
  133.  
  134. Logger.log(options);
  135. return options;
  136. }
  137.  
  138. function makeJSON_(object, options) {
  139. if (options.format == FORMAT_PRETTY) {
  140. var jsonString = JSON.stringify(object, null, 4);
  141. } else if (options.format == FORMAT_MULTILINE) {
  142. var jsonString = Utilities.jsonStringify(object);
  143. jsonString = jsonString.replace(/},/gi, '},\n');
  144. jsonString = prettyJSON.replace(/":\[{"/gi, '":\n[{"');
  145. jsonString = prettyJSON.replace(/}\],/gi, '}],\n');
  146. } else {
  147. var jsonString = Utilities.jsonStringify(object);
  148. }
  149. if (options.language == LANGUAGE_PYTHON) {
  150. // add unicode markers
  151. jsonString = jsonString.replace(/"([a-zA-Z]*)":\s+"/gi, '"$1": u"');
  152. }
  153. return jsonString;
  154. }
  155.  
  156. function displayText_(text) {
  157. var app = UiApp.createApplication().setTitle('Exported JSON');
  158. app.add(makeTextBox(app, 'json'));
  159. app.getElementById('json').setText(text);
  160. var ss = SpreadsheetApp.getActiveSpreadsheet();
  161. ss.show(app);
  162. return app;
  163. }
  164.  
  165. // getRowsData iterates row by row in the input range and returns an array of objects.
  166. // Each object contains all the data for a given row, indexed by its normalized column name.
  167. // Arguments:
  168. // - sheet: the sheet object that contains the data to be processed
  169. // - range: the exact range of cells where the data is stored
  170. // - columnHeadersRowIndex: specifies the row number where the column names are stored.
  171. // This argument is optional and it defaults to the row immediately above range;
  172. // Returns an Array of objects.
  173. function getRowsData_(sheet, options) {
  174. var headersRange = sheet.getRange(1, 1, sheet.getFrozenRows(), sheet.getMaxColumns());
  175. var headers = headersRange.getValues()[0];
  176. var dataRange = sheet.getRange(sheet.getFrozenRows()+1, 1, sheet.getMaxRows(), sheet.getMaxColumns());
  177. var objects;
  178. if (options.normalize === 'true'){
  179. objects = getObjects_(dataRange.getValues(), normalizeHeaders_(headers));
  180. }
  181. else{
  182. objects = getObjects_(dataRange.getValues(), headers);
  183. }
  184. if (options.structure == STRUCTURE_HASH) {
  185. var objectsById = {};
  186. objects.forEach(function(object) {
  187. objectsById[object.id] = object;
  188. });
  189. return objectsById;
  190. } else {
  191. return objects;
  192. }
  193. }
  194.  
  195. // getColumnsData iterates column by column in the input range and returns an array of objects.
  196. // Each object contains all the data for a given column, indexed by its normalized row name.
  197. // Arguments:
  198. // - sheet: the sheet object that contains the data to be processed
  199. // - range: the exact range of cells where the data is stored
  200. // - rowHeadersColumnIndex: specifies the column number where the row names are stored.
  201. // This argument is optional and it defaults to the column immediately left of the range;
  202. // Returns an Array of objects.
  203. function getColumnsData_(sheet, range, rowHeadersColumnIndex, options) {
  204. rowHeadersColumnIndex = rowHeadersColumnIndex || range.getColumnIndex() - 1;
  205. var headersTmp = sheet.getRange(range.getRow(), rowHeadersColumnIndex, range.getNumRows(), 1).getValues();
  206. var headers;
  207. if (options.normalize === 'true'){
  208. headers = normalizeHeaders_(arrayTranspose_(headersTmp)[0]);
  209. }
  210. else{
  211. headers = arrayTranspose_(headersTmp)[0];
  212. }
  213. return getObjects(arrayTranspose_(range.getValues()), headers);
  214. }
  215.  
  216.  
  217. // For every row of data in data, generates an object that contains the data. Names of
  218. // object fields are defined in keys.
  219. // Arguments:
  220. // - data: JavaScript 2d array
  221. // - keys: Array of Strings that define the property names for the objects to create
  222. function getObjects_(data, keys) {
  223. var objects = [];
  224. for (var i = 0; i < data.length; ++i) {
  225. var object = {};
  226. var hasData = false;
  227. for (var j = 0; j < data[i].length; ++j) {
  228. var cellData = data[i][j];
  229. if (isCellEmpty_(cellData)) {
  230. continue;
  231. }
  232. object[keys[j]] = cellData;
  233. hasData = true;
  234. }
  235. if (hasData) {
  236. objects.push(object);
  237. }
  238. }
  239. return objects;
  240. }
  241.  
  242. // Returns an Array of normalized Strings.
  243. // Arguments:
  244. // - headers: Array of Strings to normalize
  245. function normalizeHeaders_(headers) {
  246. var keys = [];
  247. for (var i = 0; i < headers.length; ++i) {
  248. var key = normalizeHeader_(headers[i]);
  249. if (key.length > 0) {
  250. keys.push(key);
  251. }
  252. }
  253. return keys;
  254. }
  255.  
  256. // Normalizes a string, by removing all alphanumeric characters and using mixed case
  257. // to separate words. The output will always start with a lower case letter.
  258. // This function is designed to produce JavaScript object property names.
  259. // Arguments:
  260. // - header: string to normalize
  261. // Examples:
  262. // "First Name" -> "firstName"
  263. // "Market Cap (millions) -> "marketCapMillions
  264. // "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
  265. function normalizeHeader_(header) {
  266. var key = "";
  267. var upperCase = false;
  268. for (var i = 0; i < header.length; ++i) {
  269. var letter = header[i];
  270. if (letter == " " && key.length > 0) {
  271. upperCase = true;
  272. continue;
  273. }
  274. if (!isAlnum_(letter)) {
  275. continue;
  276. }
  277. if (key.length == 0 && isDigit_(letter)) {
  278. continue; // first character must be a letter
  279. }
  280. if (upperCase) {
  281. upperCase = false;
  282. key += letter.toUpperCase();
  283. } else {
  284. key += letter.toLowerCase();
  285. }
  286. }
  287. return key;
  288. //return header;
  289. }
  290.  
  291. // Returns true if the cell where cellData was read from is empty.
  292. // Arguments:
  293. // - cellData: string
  294. function isCellEmpty_(cellData) {
  295. return typeof(cellData) == "string" && cellData == "";
  296. }
  297.  
  298. // Returns true if the character char is alphabetical, false otherwise.
  299. function isAlnum_(char) {
  300. return char >= 'A' && char <= 'Z' ||
  301. char >= 'a' && char <= 'z' ||
  302. isDigit_(char);
  303. }
  304.  
  305. // Returns true if the character char is a digit, false otherwise.
  306. function isDigit_(char) {
  307. return char >= '0' && char <= '9';
  308. }
  309.  
  310. // Given a JavaScript 2d Array, this function returns the transposed table.
  311. // Arguments:
  312. // - data: JavaScript 2d Array
  313. // Returns a JavaScript 2d Array
  314. // Example: arrayTranspose([[1,2,3],[4,5,6]]) returns [[1,4],[2,5],[3,6]].
  315. function arrayTranspose_(data) {
  316. if (data.length == 0 || data[0].length == 0) {
  317. return null;
  318. }
  319.  
  320. var ret = [];
  321. for (var i = 0; i < data[0].length; ++i) {
  322. ret.push([]);
  323. }
  324.  
  325. for (var i = 0; i < data.length; ++i) {
  326. for (var j = 0; j < data[i].length; ++j) {
  327. ret[j][i] = data[i][j];
  328. }
  329. }
  330.  
  331. return ret;
  332. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement