Can Drive export spreadsheet data to JSON? - google-drive-api

Or any other parseable format such as XML. Currently only spreadsheet formats such as Excel, OO seem to be supported.

Can't be done directly, but the following Apps-script will convert a sheet to JSON within the spreadsheet. That JSON sheet can then be exported such that a client app can download it.
/**
* Retrieves all the rows in the active spreadsheet that contain data and logs the
* values for each row.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
NB Sheet 1 must be JSON and it is this sheet which is published as text to the app
Sheet 2 is the Java string version of Sheet 1
*/
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
var jsonOutput="";
/**
* main function
*/
function createJson() {
jsonOutput = "{nEwLiNe";
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var startSheet = 2;
for (var i = startSheet; i < sheets.length; i++) { // foreach sheet (except first two)
if (i > startSheet) {
jsonOutput+=",";
}
doSheet(sheets[i]);
}
jsonOutput += "nEwLiNe}";
Logger.log("nEwLiNenEwLiNe==nEwLiNenEwLiNenEwLiNe"+jsonOutput);
// write the output to A1
SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange("A1").setValue(jsonOutput.replace(/nEwLiNe/g," "));
// write a Java string to B1
var java='jsonS = "'+jsonOutput.replace(/"/g,'\\"').replace(/nEwLiNe/g,' ')+'";';
SpreadsheetApp.getActiveSpreadsheet().getSheets()[1].getRange("A1").setValue(java);
};
/**
* for each sheet
*/
function doSheet(sheet) {
jsonOutput+="nEwLiNe";
jsonOutput+='"'+sheet.getName()+'" : '
var rows = sheet.getDataRange();
var values = rows.getValues();
var rowCount=values.length;
// look for a blank column which is the end of columns to process,ie any extra columns to the right are ignored
var colCount=values[0].length;
for (var c = 0; c < colCount; c++) {
// Logger.log(values[0][c]);
if (values[0][c] == "" || values[0][c] == null) {
colCount=c;
break;
}
}
if (rowCount > 2) {
jsonOutput+="nEwLiNe[";
}
for (var r = 1; r < rowCount; r++) { // for each data row
if (r>1) {
jsonOutput+=',';
}
jsonOutput+='nEwLiNe{nEwLiNe';
for (var c = 0; c < colCount; c++) {
if (c==0) {
jsonOutput+='nEwLiNe';
} else {
jsonOutput+=',nEwLiNe';
}
var n=values[0][c].replace(/^\s+|\s+$/g, "");
var v=(""+values[r][c]).replace(/^\s+|\s+$/g, "");
v=v.replace(/\n/g,"").replace(/\r/g,"");
// Logger.log(sheet.getName()+":"+r+" "+n+":"+v);
jsonOutput+=' "'+n+'" : "'+v+'"'
}
jsonOutput+='nEwLiNe}nEwLiNe';
}
if (rowCount > 2) {
jsonOutput+="nEwLiNe]nEwLiNe";
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Create JSON",
functionName : "createJson"
}];
sheet.addMenu("Tmph", entries);
};

If it is a Google Sheet you can export parseable XML through the Google Sheet API (https://developers.google.com/google-apps/spreadsheets/) using a list based feed or a cell based feed.

Related

Google Sheets Get Editors of Cell Without Having to First Protect Cell

Is there a way to get the current editors of a cell without having to first set permissions? The code I have below resets the permissions to the sheet default and then grabs that as the current editors as opposed to using the editors that were there before overwriting that cell with protect().
function onEdit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var name = sheet.getRange("A4:A52").getValues();
var setPermissions = [];
//Employee preferred initials in order to match last name array
var initialsToMatchLastName = ['CC','RR'];
//Employee last names
var lastNames = ['Charles','Rickey'];
var emails = ['charles#email.com','rickey#email.com'];
name.forEach((value,v) => {
for (var i = 0; i < lastNames.length; i++) {
if (value[0] == lastNames[i]) {
var protection = sheet.getRange("R" + (v + 4)).protect().setDescription('Locked_' + lastNames[i] + '_' + v);
var users = protection.getEditors();
//Logger.log(users);
//Logger.log(emails[i]);
if (users.includes(emails[i])) {
//Do nothing.
} else {
protection.removeEditors(users);
protection.addEditor(emails[i]);
}
}
}
})
}

Removing 'undefined' from output before writing to Google Sheets

My script below returns 'undefined' to the Google Sheet when I add dfStatus.error.count to the array to be written.
function getDatafeedStatus() {
var d = new Date();
var ar = [];
for (var a in FEEDS) {
for (var i = 0; i < FEEDS[a].length; i++) {
try {
var dfStatus = ShoppingContent.Datafeedstatuses.get(a, FEEDS[a][i]);
// see https://developers.google.com/shopping-content/v2/reference/v2/datafeedstatuses for detail on this API call
ar.push([d, a, FEEDS[a][i], dfStatus.processingStatus, dfStatus.lastUploadDate, dfStatus.itemsValid, dfStatus.errors.count]);
} catch (e) {
Logger.log(e.message); // check View > Logs after running the script if a feed does not appear to be fetching correctly
}
}
}
appendArrayToSheet(ar, 'status');
}
/**
* Add an array to the bottom of a sheet. If the sheet doesn't exist, it is created.
* #param {array} ar - the array to write
* #param {string} sheetName - the name of the sheet to which to write
*/
function appendArrayToSheet(ar, sheetName){
if (ar.length !== 0 && ar[0].length !== 0){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
if (sheet == null) {
sheet = ss.insertSheet();
sheet.setName(sheetName);
};
var range = sheet.getDataRange();
var row = range.getLastRow() + 1;
var newRange = sheet.getRange(row, 1, ar.length, ar[0].length);
newRange.setValues(ar);
}
Any ideas whats wrong with it? I must say I'm not a JavaScript expert. I'm trying modify the code which is already used somewhere else.

Zillow and Google Script

I have a script that pulls data from Zillow into a google doc....see below. It has worked fine for a couple of years but recently stopped working. It appears to run but takes a long time and no data is populated. The Zillow ID is located in Column B of the active sheet and according to the script the Zestimate should be written in Column 48. I've replaced my ZWS-ID with "X1-XXXXXXXXX_XXXX"
Any help is greatly appreciated.
Thanks
KIWI
function getZillowEstimates() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var specificRow = ""
var endRow;
if(specificRow == "")
{
specificRow = 1;
endRow = numRows;
}
else
{
specificRow = specificRow - 1;
endRow = specificRow;
}
for (var i = specificRow; i <= endRow; i++)
{
try
{
var row = values[i];
var response = UrlFetchApp.fetch("http://www.zillow.com/webservice/GetZestimate.htm?zws-id=X1-XXXXXXXXX_XXXX&zpid=" + row[1]);
var xmlDoc = XmlService.parse(response.getContentText());
var documentElement = xmlDoc.getRootElement();
var destinationRange = sheet.getRange(i + 1, 48, 1, 1);
if( null != documentElement )
{
var responseElement = documentElement.getChild("response");
if (null != responseElement)
{
var zestimateElement = responseElement.getChild("zestimate");
if( null != zestimateElement)
{
var amountElement = zestimateElement.getChild("amount");
if( null != amountElement)
{
var rowValue = [];
var cellValue = [];
cellValue.push(amountElement.getText());
}
}
}
}
else
{
cellValue.push("Not Found");
}
rowValue.push(cellValue);
destinationRange.setValues(rowValue);
}
catch(exception)
{
}
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var menuItems = [
{name: 'Get ZEstimate', functionName: 'getZillowEstimates'},
];
spreadsheet.addMenu('Zestimates', menuItems)
};
Today it is working. Yesterday the script was taking 6 minutes to run, today 1.6 seconds. I'm guessing there was a problem with Zillow or with the API.

Time driven function in Google script

I am trying to download the data from a website every hour using Google script. The code is shown as below. When I manually run the function CSV_sgj, I can receive the desired information in email. But when I set the function as time driven (every hour), what I get are all #VALUE!.
I found a similar question and tried to change
var sheet = SpreadsheetApp.getActiveSheet();
to
var sheet = SpreadsheetApp.openById("0AtAYfCLk3-h7dDBnckdSZkNXbkZBLXBHV200SGtuZnc");
but it still does not work.
Many thanks in advance for help!
The full code is below.
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function CSV_sgj() {
readRows();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("A1:N32");
var data = range.getValues();
var csv = "";
for (var i = 0; i < data.length; ++i) {
csv += data[i].join(",") + "\r\n";
}
var csvFiles = [{fileName:"PSI5.csv", content:csv}]
MailApp.sendEmail("xxxxxx#gmail.com", "CSV", "", {attachments: csvFiles});
}
When you use
var sheet = SpreadsheetApp.openById("0AtAYfCLk3-h7dDBnckdSZkNXbkZBLXBHV200SGtuZnc");
the returned value is a spreadsheet object and what you want is a sheet object...
So you have to get the sheet by its name or by its index number. I suggest you change the variable names accordingly to keep things clear :
var ss= SpreadsheetApp.openById("0AtAYfCLk3-h7dDBnckdSZkNXbkZBLXBHV200SGtuZnc");
var sheet = ss.openByName('sheet1');// or any name you use (a string)
//or by its index
var sheet = ss.getSheets()[0] ;// 0 is the index of the first sheet in the spreadsheet (integer)

Need help creating For loop in Script editor to make Script run code on all sheets in a Google Spreadsheet

I have a script that I am trying to run on all sheets within a google doc and dont know how to make that work. IT works for one sheet, but I have numerous sheets all with the same format that need to be checked. Thanks.
Here's the script I am trying to apply to all sheets.
function sendEmail(email_address, email_subject, email_message) {
MailApp.sendEmail(email_address, email_subject, email_message);
}
function timestamp() {
return new Date()
}
var EMAIL_SENT = "EMAIL_SENT";
function test_sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.setActiveCell('A2');
var criterion_cutoff = 5;
var i = 0;
var startRow = 2;
var addr;
var subj;
var msg;
var timecheck
do {
addr = cell.offset(i,0).getValue();
subj = cell.offset(i,1).getValue();
msg = cell.offset(i,2).getValue();
criterion = cell.offset(i,3).getValue();
timecheck = cell.offset(i,11).getValue();
if (timecheck > 0) {
if(criterion < criterion_cutoff) {
sendEmail(addr,subj,msg);
Browser.msgBox('Sending email to: ' + addr);
}}
i++;
} while( cell.offset(i, 0).getValue().length > 0 )
sheet.getRange(2, 5).setValue(timestamp());
Browser.msgBox('Done!');
}
You can use an array of IDs that you want to apply the script to by making the following changes:
1. Change
function test_sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
to:
function test_sendEmail(sheetID) {
var sheet = SpreadsheetApp.openById(sheetID);
2 . Define an array of IDs of sheets that you want to change:
var idArray = [Spreadsheet1_id, Spreadsheet2_id, ...];
3 . create a loop that would cycle through all the elements of the array
for(var k in idArray) test_sendEmail(idArray[i]);
If you don't want to manually populate the idArray, you can create a function that would pull IDs of all spreadsheets in your Google Drive. If that is what you want, then use the following code instead of the line of code I provided you with in point 2.
var sprArr = DocsList.getFilesByType("spreadsheet");
var idArray;
for(var k in sprArr) idArray.push(sprArr[i].getId());