I am trying to read a spreadsheet using google spreadsheet api.
Everything went well, but when I put russian or arabic texts in the spreadsheet
my program prints ?????? ?? ????? values for those cell values.
below is the code to read spreadsheet from my google account.
SpreadsheetService service = new SpreadsheetService("MyApp");
service.setUserCredentials(USERNAME, PASSWORD);
URL feedUri = new URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full?title-exact=true&title=internationalization_contents");
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = service.getFeed(feedUri, SpreadsheetFeed.class);
List<SpreadsheetEntry> spreadsheets = feed.getEntries();
SpreadsheetEntry spreadsheet = spreadsheets.get(0);
// get the first work sheet
WorksheetEntry workSheet = spreadsheet.getWorksheets().get(0);
URL cellFeedUrl = workSheet.getCellFeedUrl();
CellFeed cellFeed = service.getFeed(cellFeedUrl, CellFeed.class);
List<CellEntry> entries = cellFeed.getEntries();
for (int n = 0; n < entries.size(); n++) {
Cell cell = entries.get(n).getCell();
System.out.println(cell.getValue());
}
this prints something like
title
welcome
???? ?? ????
anybody knows how to get characters properly to my java application.
Related
I'm currently have a Google Sheet (Pushed to a website via PHP) with all my clients beer data. I'd like to take that data and copy it into a Google Doc Template for easy printing. In my example I can move the first row of data from the Sheet into the Doc but all the other rows from the sheet do not copy over.
I could use some help with the forEach statement, I'm thinking I need to parse the array and iterate through it in a different way than I'm currently attempting. (First time using Apps Script)
Here is what I've currently coded up.
function onOpen() {
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu('Print Menu');
menu.addItem('Create New Print Menu', 'createNewMenu')
menu.addToUi();
}
function createNewMenu() {
//Google Doc Template ID and Where to Save the New File
const googleDocTemplate = DriveApp.getFileById('1xzlvVOSW_LsgOrm2N2o1-FKYzfqp_2EAbhqrLTn53yk');
const destinationFolder = DriveApp.getFolderById('11HU0TvSPMMXUZaK5gTgg8jvofxTTt02j');
//Get all spreadsheet sheets and add values as 2D arrays.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Draft List');
const rows = sheet.getDataRange().getValues();
//Create date for new filename.
const dateData = new Date();
const curr_date = dateData.getDate();
const curr_month = dateData.getMonth() + 1; //Months are zero based
const curr_year = dateData.getFullYear();
const theDate = curr_year + "-" + curr_month + "-" + curr_date;
const newFileName = theDate + ' - Bar Print Menu';
//Using the row data in a template literal, we make a copy of our template document in our destinationFolder
const copy = googleDocTemplate.makeCopy(newFileName, destinationFolder)
//Once we have the copy, we then open it using the DocumentApp
const doc = DocumentApp.openById(copy.getId())
//All of the content lives in the body, so we get that for editing
const body = doc.getBody();
rows.forEach(function(rowData) {
//In these lines, we replace our template replacement tokens with values from our spreadsheet rows.
body.replaceText('{{onTapName}}', rowData[0]);
body.replaceText('{{onTapDescription}}', rowData[1]);
body.replaceText('{{onTapPrice}}', rowData[2]);
//Logger.log(rowData);
});
//We make our changes permanent by saving and closing the document
doc.saveAndClose();
}
This code will create a copy of the template file, copy the first row of data from Google Sheets and paste it into the template in the {{onTapName}}, {{onTapDescription}} & {{onTapPrice}} areas but the other rows from the Google Sheet do not copy over.
- Screenshot of Google Sheet, Google Doc Template and Result after running above code
If I uncomment out the "Logger.log(rowData);" line, I can see the code is going through each line of the data from the Google Sheet.
- Screenshot of Execution Log
How do I modify this forEach area to copy through each line of code into the template? I feel like I'm missing something very obvious here.
Thanks in advance for the help.
I have linked part of a sheet in google doc (as linked object). Now, whenever I change the sheet data, I can click a button in google doc and the data is reflected in the google doc linked sheet too (this is all built in google doc stuff).
What I want to do is the other side of this. I am able to see a bunch of data in one place (google doc) based on the sheets I have linked. I would like to update the data in the google doc, and "upload" it to the linked google sheets.
I am trying to write a script to do that. But cannot seem to find any method to access linked sheets. I found this slides API page that can does the sheet -> slide syncing.
I am looking at the document API page, but I scanning through add... and get... methods, I don't see to find any way to get linked objects. Is it represented as NamedRange? If so, how do I access it?
There was another similar question, but without any satisfactory answer.
If you can share some pointers to get started, I would appreciate it.
Edit: Here is an example doc (and a spreadsheet contained their in) to explain the situation clearer.
Test document for updating spreadsheet - Google Docs
You can find the Table elements in your Document via findElement(elementType). If that's the only Table in your Document, as in the sample you shared, this is immediate.
Once you retrieve the Table, you can loop through its rows and cells and come up with a 2D array with the values from the table:
function getTableValues() {
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
const table = body.findElement(DocumentApp.ElementType.TABLE).getElement();
let tableValues = [[]];
for (let i = 0; i < table.getNumRows(); i++) {
const tableRow = table.getRow(i);
for (let j = 0; j < tableRow.getNumCells(); j++) {
const tableCell = tableRow.getCell(j);
const text = tableCell.getText();
tableValues[i].push(text);
}
if (i == table.getNumRows() - 1) break;
tableValues.push([]);
}
return tableValues;
}
Once you've done that, you just need to copy it to your spreadsheet via setValues(values):
function copyToSheet(tableValues, spreadsheetId) {
const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName("Sheet1");
sheet.getRange(1, 1, tableValues.length, tableValues[0].length).setValues(tableValues);
}
Calling both of these in the same function, you would get this:
function main() {
const tableValues = getTableValues();
const spreadsheetId = "{your-spreadsheet-id}";
copyToSheet(tableValues, spreadsheetId);
}
Note:
getActiveDocument() is used to retrieve the Document, so this assumes the script is bound to your Document. If that's not the case, use openById(id) or openByUrl(url) instead.
I need to transfer ownership of thousands of files I own to someone else with editing access, but I've learned that Google Drive requires you to do this one file at a time. With intermediate but growing JS experience I decided to write a script to change the owner from a list of file IDs in a spreadsheet, however I've run into trouble and I have no idea why. The debugger just runs through the script and everything looks sound for me. I'd greatly appreciate any help.
function changeOwner() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/********/').getSheetByName('Sheet1');
var range = ss.getRange(1,1,2211);
for (i = 0; i < range.length; i++){
var file = range[i][0].getValue();
var fileid = DriveApp.getFileById(file);
fileid.setOwner('******#gmail.com');
}
}
Tested below code working fine with IDs,
function myFunction() {
var spreadsheet = SpreadsheetApp.openById('ID');
var range = spreadsheet.getDataRange().getValues();
for (i = 0; i < range.length; i++){
var file = range[i][0].toString();
var fileid = DriveApp.getFileById(file);
fileid.setOwner('***#gmail.com');
}
}
Your issue is that the Range class had no length property. Instead, perform a getValues() call on the range to efficiently create a JavaScript array, and iterate on it:
function changeOwner() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/********/').getSheetByName('Sheet1');
var values = ss.getRange(1, 1, 2211).getValues();
for (i = 0; i < values.length; ++i){
var fileid = value[i][0];
var file = DriveApp.getFileById(fileid);
file.setOwner('******#gmail.com');
}
}
There are other improvements you can make, such as:
dynamic range read (rather than the fixed assumption of 2211 rows of data)
writing to a second array to keep track of which files you have yet to process
checks for if the file exists
checks for if the file is actually owned by you
checks for execution time remaining, to allow serializing any updates/tracking you do that prevents the next execution from repeating what you just did
and so on. I'll let you research those topics, and the methods available in Apps Script documentation for the DriveApp, SpreadsheetApp, Sheet, and Range classes. Note that you also have all features of Javascript 1.6 available, so many of the things you find on a Javascript Developer Reference (like MDN) are also available to you.
I'm trying to get images from google places. All is working for details: reviews, address... but when I try to get photos, I get a 404.
if(place.photos != null){
for(var i = 0; i < place.photos.length; i++){
var str = place.photos[i].getUrl({"maxWidth": 100, "maxHeight": 100});
var res = str.replace("w100-h100-p", "p");
self.pacPhotos.push({
id : res
});
}
}else {
console.log("no photo");
}
}
This will return the list ok but the URL is formatted wrong. it comes out like this.
" https://lh3.googleusercontent.com/w100-h100-p/AF1QipN3xzffYDPCyEIWnvAQGd3RwNs2C14sVlSqrrAh=k "
What I gather it wants is this.
" https://lh3.googleusercontent.com/p/AF1QipN3xzffYDPCyEIWnvAQGd3RwNs2C14sVlSqrrAh=k "
The only difference is the "w100-h100-"
*** There is a great work-around here from "Sulyman". I know it's not a long term solution as I'm sure google will fix their results (as discussed here Place API - getting place photo as marker icon )
For now I've adjusted the code above to reflect Sulymans suggestion. ***
it seems like every API Key generates different path
for example you got w100-h100-p and i got w200-p
and the good news that this section whatever it is...is fixed so you can replace it with another string which is p
var str = place.photos[0].getUrl();
var res = str.replace(""w100-h100-p", "p");
or you can delete the w100-h100-
I'm trying to create skype tool and I'm trying to make a command for it what would give the user a random imgur link, I tried first to just random generate string like so:
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[8];
var random = new Random();
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
string imgur = "http://imgur.com/" + finalString;
But of course it just gave me random imgur links which don't work, how could I check if the link is valid and then give it to the user or how could I use imgurs own "https://imgur.com/gallery/random" and return the link from that?
Imgur API exposes a function to fetch a random set of gallery images:
https://api.imgur.com/endpoints/gallery#gallery-random
Method GET
Route https://api.imgur.com/3/gallery/random/random/{page}