I've searched high and wide for an answer but can't seem to find it. I am trying to alter my custom function that looks up sitemap URL's and the date they were updated to accept a range of inputs.
Here is the current function that works:
function sitemap(sitemapUrl, namespace) {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9");
var urls = root.getChildren('url', sitemapNameSpace);
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc', sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod', sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
return array;
}
I've tried using Google's example below but doesn't seem to work however I incorporate it into my function. Any ideas?
function DOUBLE(input) {
if (input.map) { // Test whether input is an array.
return input.map(DOUBLE); // Recurse over array if so.
} else {
return input * 2;
}
}
Edit: This is how I tried to use Google's example for my function:
function sitemaps(sitemapUrl) {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement()
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9")
var urls = root.getChildren('url', sitemapNameSpace)
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc',sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod',sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
if (sitemapUrl.map) {
return sitemapUrl.map(sitemaps);
} else {
return array
}
You are no using the same format as the Google example. As of right now you are checking if the input is an array after actually retrieving the data.
But you using fetch with an array as input could trigger an Error and the function may no get to the point where it checks if the sitemapUrl can be used with map.
Also take into account that map will call the function in every single element of the array and return an array with a result for each of element. So in your case B3:B6 would call the function for the value at B3, B4, B5 and B6 and return an array of length 4 with the result. For your case in which you want a single list you need to flattern the array afterwards
I would change your function to be like this:
function sitemaps(sitemapUrl) {
if (sitemapUrl.map) {
return sitemapUrl.map(sitemaps).flat();
} else {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement()
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9")
var urls = root.getChildren('url', sitemapNameSpace)
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc', sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod', sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
return array
}
}
Although what you are doing is fine take into account that it also exists a way to retrieve all the request at the same time (
UrlFetchApp.fetch()) but for this specific case you would need to flatten a reshape the input array.
Observe:
var groupedLinks = new Array;
for(var i = 0; i < 5; i++) {
linkName = "59notgonnawork" + i;
groupedLinks[linkName] = new Array;
}
I would have expected the result to be the array groupedLinks to be filled up with 5 new keys, the value would be 5 empty arrays.
The actual result in extendscript would be ... grouplinks ... empty.
If I would change this example to be:
var groupedLinks = new Array;
for(var i = 0; i < 5; i++) {
linkName = "notgonnawork" + i;
groupedLinks[linkName] = new Array;
}
It would work perfectly. The only change is the missing "59" at the start of the string used for the array key.
Note that this works perfectly when I run it in console for chrome or firefox. It seems to be indesign and/or extendscript fooling around.
Anything have any ideas why ? I've meanwhile worked around the problem but I'm intrigued.
I would have expected the result to be the array groupedLinks to be filled up with 5 new keys, the value would be 5 empty arrays.
That's exactly what it does, but the way you're viewing the data is likely concealing it because you're not using the proper data structure. Also, property access won't work without using [] because identifiers may not start with a number, so you'd need:
groupedLinks["59notgonnawork0"]
What you're doing isn't meant for arrays, which are expecting sequential numeric indices (though they can technically be assigned other properties too). The type of structure you should be using is a plain object instead.
var groupedLinks = {};
for(var i = 0; i < 5; i++) {
const linkName = "59notgonnawork" + i;
groupedLinks[linkName] = new Array; // Array? plain Object? Depends on its use.
}
Why not trying to push the value in the array on each iteration.
var groupedLinks = new Array;
for(var i = 0; i < 5; i++) {
linkName = "59notgonnawork" + i;
groupedLinks.push(linkName);
}
ExtendScript Arrays are great for stocking data per indeces. If you need key/values objects, why not use… Objects ?
var groupedLinks = {};
for(var i = 0; i < 5; i++) {
linkName = "59notgonnawork" + i;
groupedLinks[linkName] = "Whatever…";
}
alert( groupedLinks["59notgonnawork0" ] ); //"Whatever…"
What is the best way to consolidate this code? As it is, it works perfectly, but it needs to go up to maybe 40-50 items long, so it needs to be shortened dramatically, (I assume, with a for loop).
I'm pretty much a novice when it comes to Javascript, and trying to add arrays to an array with a loop is confusing me immensely.
The "vac1.", "vac2." ...etc, variables are used later on in the code to add pointers onto a Google Maps map.
var x = count.count; // x = a value that changes (between 1 & 50)
if(x == 1){
locations = [
[vac1.vacancy_title, vac1.vacancy_latlng, vac1.vacancy_url, vac1.vacancy_location]
];
}
if(x == 2){
locations = [
[vac1.vacancy_title, vac1.vacancy_latlng, vac1.vacancy_url, vac1.vacancy_location],
[vac2.vacancy_title, vac2.vacancy_latlng, vac2.vacancy_url, vac2.vacancy_location]
];
}
if(x == 3){
locations = [
[vac1.vacancy_title, vac1.vacancy_latlng, vac1.vacancy_url, vac1.vacancy_location],
[vac2.vacancy_title, vac2.vacancy_latlng, vac2.vacancy_url, vac2.vacancy_location],
[vac3.vacancy_title, vac3.vacancy_latlng, vac3.vacancy_url, vac3.vacancy_location]
];
}
...etc etc...
I have tried using a for loop, but it doesn't work and I have no idea if I am anywhere close to figuring out how to do it correctly.
var x = count.count;
locations = [];
array = [];
for (i = 0; i < x; i++) {
array = [vac[i].vacancy_title, vac[i].vacancy_latlng, vac[i].vacancy_url, vac[i].vacancy_location];
locations.push(array);
}
Any help or advice would be greatly appreciated!
Thank you.
You need to consider them as a string:
var x = 5;
locations = [];
array = [];
for (i = 1; i <= x; i++) {
array = ['vac'+i+'.vacancy_title', 'vac'+i+'.vacancy_latlng', 'vac'+i+'.vacancy_url', 'vac'+i+'.vacancy_location'];
locations.push(array);
}
console.log(locations);
Create an array vac and use your previous code :
var x = count.count;
locations = [],
array = [],
vac = [ /* vac1, vac2, ...., vacn */ ];
for (i = 0; i < x; i++) {
array = [vac[i].vacancy_title, vac[i].vacancy_latlng, vac[i].vacancy_url, vac[i].vacancy_location];
locations.push(array);
}
You could use eval for the variable name and build an new array with another array for the wanted keys.
Basically you should reorganize yor program to use a solution without eval. An array could help. It is made for iteration.
var x = count.count,
i,
keys = ['vacancy_title', 'vacancy_latlng', 'vacancy_url', 'vacancy_location'],
locations = [];
object;
for (i = 1; i <= x; i++) {
object = eval('vac' + i);
locations.push(keys.map(function (k) { return object[k]; }));
}
Group the vac* elements in an array and then use slice to cut out as many as you want, then use map to generate the result array:
var vacs = [vac1, vac2 /*, ...*/]; // group the vacs into one single array
var x = count.count; // x is the number of vacs to generate
var locations = vacs.slice(0, x).map(function(vac) { // slice (cut out) x elements from the arrays vacs then map the cut-out array into your result array
return [vac.vacancy_title, vac.vacancy_latlng, vac.vacancy_url, vac.vacancy_location];
});
Because any global variable is a property of the global object :
var vac1 = "whatever";
console.lof(window.vac1); // => logs "whatever"
console.lof(window["vac1"]); // => accessed as an array, logs "whatever" too
You could use the global object and access it as an array to look for your vac1, vac2, vac3 variables :
var x = count.count, i;
locations = [],
array = [],
var globalObject = window; // or whatever the global object is for you
var vac; // this will be used to store your vac1, vac2, etc.
for (i = 0; i < x; i++) {
vac = globalObject["vac"+i]; // the "vac" + i variable read from the global object
if (vac !== undefined) {
array = [vac.vacancy_title, vac.vacancy_latlng, vac.vacancy_url, vac.vacancy_location];
locations.push(array);
}
}
I have leaflet object _test which looks like this
There are 4050 elements, and for all those elements I tried to run a loop and place label
var a = Object.keys(_test);
console.log(a.length);
j = 0;
for (var i = 0; i < a.length - 1; i++) {
var b = _test[a[i]];
var vdc = L.polygon(b._latlngs);
vdc_name = b.feature.properties.NAME_4;
var labelLocation = new L.LatLng(vdc.getBounds().getCenter().lat, vdc.getBounds().getCenter().lng);
var labelTitle = new L.LabelOverlays(labelLocation, vdc_name);
VDC_labels.addLayer(labelTitle);
console.log(vdc_name, j);
j++}
The output in console for console.log(a.length); is 4050. But the last output of
console.log(vdc_name, j);
is Sidin 1841, which means the loop runs only 1841 times. Can anyone please help me find out what i am doing wrong?
I also tried with this but the result is the same
for (ath in _test) {
var b = _test[ath];
var vdc = L.polygon(b._latlngs);
// console.log(i);
// i++
vdc_name = b.feature.properties.NAME_4; //label content
var labelLocation = new L.LatLng(vdc.getBounds().getCenter().lat, vdc.getBounds().getCenter().lng);
var labelTitle = new L.LabelOverlays(labelLocation, vdc_name);
VDC_labels.addLayer(labelTitle);
}
Solved.
Actually the problem is with the data i.e. in _test object the 1842nd element is a multipolygon unlike all other elements (polygon) so during the access of coordinate in
var b = _test[a[i]];
var vdc = L.polygon(b._latlngs);
b doesnot have the property _latlngs so the loop breaks..
I have a string like this:
string = "locations[0][street]=street&locations[0][street_no]=
34&locations[1][street]=AnotherStreet&locations[1][street_no]=43";
What must I do with this string so i can play with locations[][] as I wish?
You could write a parser:
var myStr = "locations[0][street]=street&locations[0][street_no]=34&locations[1][street]=AnotherStreet&locations[1][street_no]=43";
function parseArray(str) {
var arr = new Array();
var tmp = myStr.split('&');
var lastIdx;
for (var i = 0; i < tmp.length; i++) {
var parts = tmp[i].split('=');
var m = parts[0].match(/\[[\w]+\]/g);
var idx = m[0].substring(1, m[0].length - 1);
var key = m[1].substring(1, m[1].length - 1);
if (lastIdx != idx) {
lastIdx = idx;
arr.push({});
}
arr[idx * 1][key] = parts[1];
}
return arr;
}
var myArr = parseArray(myStr);
As Shadow wizard said, using split and eval seems to be the solution.
You need to initialize locations first, if you want to avoid an error.
stringArray=string.split("&");
for (var i=0;i<stringArray.length;i++){
eval(stringArray[i]);
}
However, you might need to pay attention to what street and street_no are.
As is, it will produce an error because street is not defined.
Edit: and you'll need to fully initialize locations with as many item as you'll have to avoid an error.