Parsing XML in Google Scripts to a google sheet - javascript

I'm trying to import data from a server, XML format via the server API, which require's a login.
Using information on this question: Cheers MogsDad
I can successful get the external xml file and data shows in the logger.
I cannot for the life of me write any of the info or elements to my spreadsheet. In the link shared, #mogsdad has linked to a parsing XML site. Unfortunately the link is dead. The current code returns an XML file. Normally I would try to use the importxml formula but not had much luck.
Have taken out my coding attempts to parse the XML so code doesn't look awful
has anyone got any pointers on how to parse some of all of the file or know a working URL for the XML parsing doc?
Here is my code so far. Thanks in advance
function importFromXml(){
var url = 'URL HERE'; // Advance search for macs not encrypted.
var username = 'USER HERE';
var password = 'PASSWORD HERE';
var headers =
{
Authorization : "Basic " + Utilities.base64Encode(username+':'+password)
}
var options =
{
"method" : "get",
"headers": headers
};
var headers =
{
Authorization : "Basic " + Utilities.base64Encode(username+':'+password)
}
var options =
{
"method" : "get",
"headers": headers
};
// Getting "bad request" here - check the username & password
var result = UrlFetchApp.fetch(url, options);
var state=result.getContentText();
// You should check state.getResponseCode()
Logger.log('1: '+state);
Logger.log(parse(state));
}
function parse(txt) {
var doc = Xml.parse(txt, true);
return doc; // Return results
}
**** EDIT ****
After a bit more playing, I have some progress.
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NoFirevault");
var range = ss.getRange(1, 1);
range.setValue(state);
I managed to write the XML contents to my sheet. Albeit in one cell. When I try to split the data into cells, using the data length and use setValues. It bums out on me, will keep on playing.
**** EDIT *****
After a bit more playing around. I can get XML data written to sheet.
There's 31 entries, with various attributes. But these all get written to a single cell per entry.
Which is an improvement on ALL 31 entries going to a single cell.
In case it helps, here is the XML layout I'm looking at.
I want the computer data, in the computers section.
function importFromJamf(){
var url = 'URL HERE'; // Advance search for macs not encrypted.
var username = 'USER HERE';
var password = 'Password';
var headers =
{
Authorization : "Basic " + Utilities.base64Encode(username+':'+password)
}
var options =
{
"method" : "get",
"headers": headers
};
var headers =
{
Authorization : "Basic " + Utilities.base64Encode(username+':'+password)
}
var options =
{
"method" : "get",
"headers": headers
};
var result = UrlFetchApp.fetch(url, options);
var state = result.getContentText();
var document = XmlService.parse(state);
var entries = document.getRootElement().getChild('computers').getChildren(); // Working but values joined into one row
for (i=0;i<entries.length;i++){
var value = entries[i].getValue();
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2").getRange(i+1,1).setValue(value);
}
}

function importFromJamf(){
var url = 'url';
var username = 'user';
var password = 'pw';
var headers =
{
Authorization : "Basic " + Utilities.base64Encode(username+':'+password)
}
var options =
{
"method" : "get",
"headers": headers
};
var result = UrlFetchApp.fetch(url, options);
var state = result.getContentText();
var document = XmlService.parse(state);
var array= [];
var entries = document.getRootElement().getChild('computers').getChildren('computer');
for(i = 0 ; i < entries.length ; i++){
var a = entries[i].getContent(5).getValue();
var b = entries[i].getContent(8).getValue();
var c = entries[i].getContent(9).getValue();
var d = entries[i].getContent(6).getValue();
var e = entries[i].getContent(11).getValue();
var f = entries[i].getContent(12).getValue();
var g = entries[i].getContent(10).getValue();
var data = [a,b, c,d,e, f,g];
array.push(data);
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
sheet.getRange("A2:Z").clearContent();
var range = sheet.getRange(2,1,array.length, array[0].length);
range.setValues(array);
}
Code above works for what I need, it allows me to grab the values I want into an array I can use to write to a sheet.
.getContent() helped me get the values of y columns of array each loop
But I'm sure there are better ways of going about it.

Related

Message saying [Ljava.lang.Object] being delivered in place of values

I'm trying to collect tweets from Twitter API V2:
https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets
The script I'm using to send the tweet value data to a Google Sheets cell is:
function TwitterTest() {
var string_Screen_name = "1310800524619386880";
var string_Consumer_key = "AAAAAAAAAAAAAAAAAAAAAAAAAA";
var string_Consumer_secret = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
var tokenUrl = "https://api.twitter.com/oauth2/token";
var tokenCredential = Utilities.base64EncodeWebSafe(string_Consumer_key + ":" + string_Consumer_secret);
var tokenOptions = {
headers : {
Authorization: "Basic " + tokenCredential,
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
method: "post",
payload: "grant_type=client_credentials"
};
var responseToken = UrlFetchApp.fetch(tokenUrl, tokenOptions);
var parsedToken = JSON.parse(responseToken);
var token = parsedToken.access_token;
var apiUrl = "";
var responseApi = "";
var apiOptions = {
headers : {
Authorization: 'Bearer ' + token
},
"method" : "get"
};
var apiUrl = 'https://api.twitter.com/2/users/'+ string_Screen_name +'/tweets?expansions=attachments.poll_ids,attachments.media_keys,author_id,entities.mentions.username,geo.place_id,in_reply_to_user_id,referenced_tweets.id,referenced_tweets.id.author_id&tweet.fields=attachments,author_id,context_annotations,conversation_id,created_at,entities,geo,id,in_reply_to_user_id,lang,possibly_sensitive,public_metrics,referenced_tweets,reply_settings,source,text,withheld&user.fields=created_at,description,entities,id,location,name,pinned_tweet_id,profile_image_url,protected,public_metrics,url,username,verified,withheld&place.fields=contained_within,country,country_code,full_name,geo,id,name,place_type&poll.fields=duration_minutes,end_datetime,id,options,voting_status&media.fields=duration_ms,height,media_key,preview_image_url,type,url,width,public_metrics,non_public_metrics,organic_metrics,promoted_metrics';
responseApi = UrlFetchApp.fetch(apiUrl, apiOptions);
var obj_data = JSON.parse(responseApi.getContentText());
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Tweets").getRange("A3").setValue(obj_data.data);
}
The result obtained:
{attachments={media_keys=[Ljava.lang.Object;#1152e2a4}, entities={urls=[Ljava.lang.Object;#1373921e}, possibly_sensitive=false, conversation_id=1402411015724175370, public_metrics={like_count=1, reply_count=0, quote_count=0, retweet_count=0}, created_at=2021-06-08T23:43:36.000Z, source=Twitter Web App, id=1402411015724175370, text=ALERT: New high roller bet posted!
A parlay bet has been placed for $5,403.62 to win $6,241.18.
To view this bet or copy it https:// t.co /lrBXjHN0At https:// t.co /nBPMsgXI2g, author_id=1310800524619386880, lang=en, reply_settings=everyone}
Specifically in urls the result is:
urls=[Ljava.lang.Object;#1373921e}
The expected result in urls would look something like (example collected from Twitter API V2 website):
In your situation, is the following modification the result you expect?
From:
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Tweets").getRange("A3").setValue(obj_data.data);
To:
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Tweets").getRange("A3").setValue(JSON.stringify(obj_data.data));

Ho do I Parse XML using Google Apps Script and loop through all elements

This is my first time working with XML and I am not that techy but trying to get to understand programming to make my work easier. I am using Google App script and finding it a challenge in passing XML data that I get via API.
I need to get this data so that I can set the specific values to Google sheets using google app script.
I am not sure how to iterate/loop through elements to get everyone's data and then set it to google sheet.
And here is the code I have worked on so far. When I log to say the first name, I only get one name instead of about 50 names in the system. Any help here will highly be appreciated.
ak ='key'
start = '2019-01-01'
end = '2019-12-31'
function getData() {
var options = {
method: 'get',
headers: {
Authorization: 'Bearer ' + ak
}
};
var url = 'https://data.purelyhr.com/daily?ak='+ ak + '&sDate=' + start + '&eDate=' + end + '&TimeOffTypeName';
var response = UrlFetchApp.fetch(url).getContentText();
var document = XmlService.parse(response);
var root = document.getRootElement();
//set variables to data from PurelyHR
var TimeOffDate = root.getChild('Request').getChild('TimeOffDate').getText();
var TimeOffDayOfWeek = root.getChild('Request').getChild('TimeOffDayOfWeek').getText();
var TimeStart = root.getChild('Request').getChild('TimeStart').getText();
var TimeEnd = root.getChild('Request').getChild('TimeEnd').getText();
var TimeOffHours = root.getChild('Request').getChild('TimeOffHours').getText();
var TimeOffTypeName = root.getChild('Request').getChild('TimeOffTypeName').getText();
var LoginID= root.getChild('Request').getChild('LoginID').getText();
var Firstname = root.getChild('Request').getChild('Firstname').getText();
var Lastname = root.getChild('Request').getChild('Lastname').getText();
var UserCategory = root.getChild('Request').getChild('UserCategory').getText();
var SubmittedDate = root.getChild('Request').getChild('SubmittedDate').getText();
var Deducted = root.getChild('Request').getChild('Deducted').getText();
var Comment = root.getChild('Request').getChild('Comment').getText();
//populate the sheet with variable data
Logger.log(response)
}
Sample response
<?xml version='1.0' encoding='ISO-8859-1'?>
<DataService>
<Request ID="1253" Status="Approved">
<TimeOffDate>2020-02-07</TimeOffDate>
<TimeOffDayOfWeek>Friday</TimeOffDayOfWeek>
<TimeStart></TimeStart>
<TimeEnd></TimeEnd>
<TimeOffHours>8.000</TimeOffHours>
<TimeOffTypeName>Annual Vacation</TimeOffTypeName>
<LoginID>testuser</LoginID>
<Firstname>test</Firstname>
<Lastname>user</Lastname>
<UserCategory></UserCategory>
<SubmittedDate>2019-10-03</SubmittedDate>
<Deducted>Yes</Deducted>
<Comment>
<![CDATA[* time-off request created by administrator]]>
</Comment>
</Request>
<Request ID="126292" Status="Approved">
<TimeOffDate>2020-02-07</TimeOffDate>
<TimeOffDayOfWeek>Friday</TimeOffDayOfWeek>
<TimeStart></TimeStart>
<TimeEnd></TimeEnd>
<TimeOffHours>8.000</TimeOffHours>
<TimeOffTypeName>Annual Vacation</TimeOffTypeName>
<LoginID>usertwo</LoginID>
<Firstname>user</Firstname>
<Lastname>two</Lastname>
<UserCategory></UserCategory>
<SubmittedDate>2019-10-15</SubmittedDate>
<Deducted>Yes</Deducted>
<Comment>
<![CDATA[Neil (as my mentor)]]>
</Comment>
</Request>
If I understand correctly, the problem is that you have multiple <Request> elements, but your code is only looking at one of them. This is because you're using getChild(), which will only provide the first element with the given name.
I can't fully test that this works because you haven't provided the XML text, but you should instead use the getChildren() method to get all of the Request elements. Then you can loop through that.
function getData() {
var options = {
method: 'get',
headers: {
Authorization: 'Bearer ' + ak
}
};
var url = 'https://data.purelyhr.com/daily?ak=' + ak + '&sDate=' + start + '&eDate=' + end + '&TimeOffTypeName';
var response = UrlFetchApp.fetch(url).getContentText();
var document = XmlService.parse(response);
var root = document.getRootElement();
//set variables to data from PurelyHR
var requestElements = root.getChildren('Request'); // Get all <Request> elements
var requestObjects = []; // Request objects for logging / eventual printing
for (var i = 0; i < requestElements.length; i++) {
var request = requestElements[i]; // A single <Request> element
// Add to requestObjects array
requestObjects.push({
TimeOffDate: request.getChild('TimeOffDate').getText(),
TimeOffDayOfWeek: request.getChild('TimeOffDayOfWeek').getText(),
TimeStart: request.getChild('TimeStart').getText(),
TimeEnd: request.getChild('TimeEnd').getText(),
TimeOffHours: request.getChild('TimeOffHours').getText(),
TimeOffTypeName: request.getChild('TimeOffTypeName').getText(),
LoginID: request.getChild('LoginID').getText(),
Firstname: request.getChild('Firstname').getText(),
Lastname: request.getChild('Lastname').getText(),
UserCategory: request.getChild('UserCategory').getText(),
SubmittedDate: request.getChild('SubmittedDate').getText(),
Deducted: request.getChild('Deducted').getText(),
Comment: request.getChild('Comment').getText()
});
}
Logger.log(JSON.stringify(requestObjects));
}
Since I don't know how you're printing, I created an array of request objects and logged that in the sample above. I hope this made sense, but please let me know if you have any questions or if I'm completely off with my response.

I am creating a dictionary in google spreadsheet

I am a newbie in coding.
I am trying to create a function in google app script that acts like a dictionary and pulls out the meaning of the word passed as the argument. Its using the API of oxford dictionaries but its not working. Its showing the error 403. "var response = UrlFetchApp.fetch(url,headers);" shows the error.
function Word_meaning(word){
var url="https://odapi.oxforddictionaries.com:443/api/v1/entries/en/" + word + "/regions=us";
var headers =
{
'Accept': 'application/json',
'app_id': 'abc',
'app_key': '123'
};
var response = UrlFetchApp.fetch(url,headers);
var data = JSON.parse(response.getContentText());
Logger.log(data);
}
A couple of things - why do you include the port number in the API call? My API endpoint for querying Oxford Dictionaries looks different. Also, there's a dash in "od-api".
https://od-api.oxforddictionaries.com/api/v1/entries/en/{word_id}/regions={region}
Testing the link in the address bar, I get the expected server response of "Authorization required" while the URL you provided doesn't seem to exist.
Anyway, the error pops up because the optional 'params' object for the UrlFetchApp.fetch(url, params) method is not constructed properly. The "headers" property must be contained within that object. Somewhat ambiguous here, but please read:
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object)
I was able to get things up and running using the code below.
function getData(word, region){
var word = word || "leprechaun";
var region = region || "us";
var wordId = encodeURI(word);
var baseUrl = "https://od-api.oxforddictionaries.com/api/v1/entries/en/{word_id}/regions={region}";
var app_id = "app_id";
var app_key = "app_key";
var headers = {
"app_id": app_id,
"app_key": app_key
};
var options = {
"headers": headers,
"muteHttpExceptions": true
};
var url = baseUrl.replace("{word_id}", wordId)
.replace("{region}", region);
var res = UrlFetchApp.fetch(url, options);
var responseCode = res.getResponseCode();
if (responseCode == 200) {
var data = JSON.parse(res.getContentText());
} else {
Logger.log(res.getContentText());
}
}

How to send json and parse it on next html page through url in jquery?

I want to send json data through url to next html page. I checked it by emulator as I am working for mobile app, the url could not redirect to next page it is crashing at the moment what is the reason behind this. How can I parse it on next page .I am new to the jquery any idea? my json data contains result of two different sql queries in an array
$.ajax({
type : "POST",
datatype : "json",
url : "http://Localhost/phpBB3/check_pass.php?username="+ username + "&password="+ password+"&f=68",
success: function(data){
alert(data);
window.location.href="source/testmenu.html?varid=" + data +"&username=" + username +"&password=" + password;
}
});
This is the code on next page
$(document).ready(function GetUrlValue(VarSearch){
var SearchString = window.location.search.substring(1);
var arr = SearchString.split('&');
console.log(arr);
//Set session variables
var username = arr[1].split('=')[1];
var password = arr[2].split('=')[1];
document.getElementById('username').value = username;
document.getElementById('password').value = password;
)};
in your case in first page urlencode json
window.location.href="source/testmenu.html?varid=" + encodeURIComponent(data) +"&username=" + username +"&password=" + password;
and in next page
var data= arr[0].split('=')[1];
var recieved_json = $.parseJSON(data);
Then try this one:
var data = {
username: username,
password: password
};
$.ajax({
type: "POST",
url: "http://Localhost/phpBB3/check_pass.php",
params: $.param(data),
success: function(a) {
window.location.href = "source/testmenu.html?"
+ $.param(a) + "&" + $.param(data)
}
});
And this would be your code for the next page (the iterator is from Satpal's answer):
$(document).ready(function() {
var params = window.location.search;
var getURLParams = function(params) {
var hash;
var json = {};
var hashes = url.slice(url.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
json[hash[0]] = hash[1];
}
return json;
}
params = getURLParams(params);
var username = params.username;
var password = params.password;
$('#username').val(username);
$('#password').val(password);
});
Though I agree with #Jai that sending username and password in url is not recommended.
Once you get the URL to load you'll need to run your data through some encoding and decoding. You might have the wrong path. If you want "http://Localhost/source/testmenu.html" make sure the first character is a "/".
Make sure your data object is encoded correctly.
// Encode data for querystring value.
var data = {
foo: "bar"
};
var data_str = JSON.stringify(data);
data_str = encodeURIComponent(data_str);
Decode and test your URL.
// Get data from querystring value.
// Get the query as an object with decoded values.
// Note that JSON values still need parsing.
function getQuery() {
var s=window.location.search;
var reg = /([^?&=]*)=([^&]*)/g;
var q = {};
var i = null;
while(i=reg.exec(s)) {
q[i[1]] = decodeURIComponent(i[2]);
}
return q;
}
var q = getQuery();
try {
var data = JSON.parse(q.data);
} catch (err) {
alert(err + "\nJSON=" + q.data);
}
Parameter should be html encode while navigating or requesting to the URL and decode at the receiving end. It may suspect potentially dangerous content which may leads to crash.

UrlFetch put method using Google Apps Script

Have tried many options to update a product in ECWID using Google Apps Script UrlFetchApp.fetch() put method but not succeeded. Following are the different ways that I've written the code and tested, but am getting different type of errors.
I guess, am missing some small thing, which am not able to figure it out. Please help me to fix this issue.
API: ECWID Products API (http://kb.ecwid.com/w/page/25285101/Product%20API#RESTAPIMethodupdateaproduct)
Method: PUT (to update the product details)
Sample Code 1:-
function updateProducts(){
var products_authkey = "xxxxxxxx";
try{
var url ="https://app.ecwid.com/api/v1/xxxxx/product?id=xxxxxxxx&secure_auth_key="+products_authkey;
var payload = {price:62755};
var options ={method:"put",ContentType:"application/json",payload:payload};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
}catch(e){
Browser.msgBox(e);
}
}
Error:-
"{ "error": "OTHER", "errorMessage": "Error parsing JSON: A JSONObject text must begin with '{' at character 0" }"
Version 2:-
Tried converting the object to json stringify, but the same error.
function updateProducts_version2(){
try{
var url ="https://app.ecwid.com/api/v1/xxxx/product?id=xxxxx&secure_auth_key="+products_authkey;
var payload = {price:62755};
var payload_json = Utilities.jsonStringify(payload);
var options ={method:"put",ContentType:"application/json",payload:payload_json,muteHttpExceptions:true};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var x = 1;
}catch(e){
Browser.msgBox(e);
}
}
Error:-
"{ "error": "OTHER", "errorMessage": "Error parsing JSON: A JSONObject text must begin with '{' at character 0" }"
Version 3:- (Tried passing secure_auth_key using Authorization in headers)
function updateProducts_version3(){
try{
var url ="https://app.ecwid.com/api/v1/xxxxx/product?id=xxxxx";
var payload = {price:62755};
var headers = {Authorization: 'xxxxxxx'};
var options = {headers:headers,method:"put",ContentType:"application/json",payload:payload};
var options ={method:"put",ContentType:"application/json",payload:payload,muteHttpExceptions:true};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var x = 1;
}catch(e){
Browser.msgBox(e);
}
}
Error:-
{ "error": "OTHER", "errorMessage": "API key not found in request parameters" }
Also to note that, I've tried using DevHttpClient chrome plugin, it's updating properly.
Which means that there's some problem the way we're using UrlFetch. Please help me in fixing this issue...
Thanks in advance...
Credentials are needed to test this, so that's up to you. You probably need to both stringify & encode the payload. You also had incorrect capitalization on contentType, which you could check with UrlFetchApp.getRequest().
function updateProducts_version2a(){
try{
var url ="https://app.ecwid.com/api/v1/xxxx/product?id=xxxxx&secure_auth_key="+products_authkey;
var payload = {price:62755};
var payload_json = encodeURIComponent(JSON.stringify(payload));
var options ={method:"put",contentType:"application/json",payload:payload_json,muteHttpExceptions:true};
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var x = 1;
}catch(e){
Browser.msgBox(e);
}
}
This next version seemed to work - by suppressing the price change and using a store's ID, it mimicked a product 'get', according to the docs you referenced. This time, the error message might be indicating some level of success: "This Ecwid account doesn't have access to Ecwid API. Please, consider upgrading it."
You'll notice that the URL has been separated out, with the basic header info of product ID and auth key together.
function updateProducts_version4(){
try{
var url ="https://app.ecwid.com/api/v1/xxxx/product";
var payload = encodeURIComponent(JSON.stringify({
price:62755
}));
var headers = {id:'xxxx',
secure_auth_key: 'xxxxxxx'
};
var options = {
headers:headers,
method:"put",
contentType:"application/json",
muteHttpExceptions:true,
payload:payload
};
var request = UrlFetchApp.getRequest(url, options); // Debug: check what would be fetched
var result = UrlFetchApp.fetch(url, options);
var response = result.getContentText();
var res_code = result.getResponseCode();
var respHeaders = result.getHeaders(); ///
debugger;
}catch(e){
Logger.log(e);
//Browser.msgBox(e);
}
}
Without your creds, that's as far as I can take it... tell us how that works for you.

Categories