How to get single value from .xml - javascript

I have some xml or excel I want to loop through this document in InDesign script and insert values on defined places
this is excel or xml
this I want to get
I don't have so much scripting experiences so I can only this piece of code
var doc = app.activeDocument;
var myFile = File("~/Desktop/test.xml");
var textExcel = doc.textFrames.add();
textExcel.geometricBounds = [50, 80, 10, 150];
textExcel.place(myFile);
but now how I can get a single value? for example in indesign template first paragraph should look like table --> lorem--> 150

Here is the possible solution:
var doc = app.activeDocument;
// get a text from the XLSX file
var inputFile = File("d:/table.xlsx");
var temp_frame = doc.textFrames.add();
temp_frame.place(inputFile);
var text = temp_frame.parentStory.contents;
temp_frame.remove();
// make a table from the text
var rows = text.split('\r');
var table = [];
for (var i = 1; i < rows.length; i++) table.push(rows[i].split('\t'));
// loop through the table and make the cards
for (var i = 0; i < table.length; i++) {
var title = table[i][0];
var description = table[i][1];
var price = table[i][2];
var card = make_card(title, description, price);
// move the card to some places
card.move([10,10]);
card.move(undefined, [i*75, 0]);
}
// the function to create and return a card
function make_card(title, description, price) {
var doc = app.activeDocument;
var title_frame = doc.textFrames.add();
title_frame.geometricBounds = [20, 80, 30, 150];
title_frame.contents = title;
var description_frame = doc.textFrames.add();
description_frame.geometricBounds = [30, 80, 80, 150];
description_frame.contents = description;
var price_frame = doc.textFrames.add();
price_frame.geometricBounds = [80, 80, 100, 150];
price_frame.contents = price;
// apply styles to the texts in the card
apply_style('title', title_frame);
apply_style('description', description_frame);
apply_style('price', price_frame);
var group = doc.groups.add([title_frame, description_frame, price_frame]);
return group;
}
function apply_style(style_name, frame) {
var doc = app.activeDocument;
try {
var style = doc.paragraphStyles.itemByName(style_name);
frame.paragraphs.everyItem().appliedParagraphStyle = style;
} catch(e) {}
}
This is the XLSX table:
Here is the result layout (3 cards):
It creates cards from XLSX file (applies the styles to the texts inside cards, why not?) and put them on the page of the current document.

You can probably do this with xpath and Document.
https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate
You create a new Document with the xml and you evaluate a xPath.

Related

How to import .xlsx to InDesign

With following code I am trying to import excel file to indesign. I can get data but if in table is more then 3 rows it just continue in line and doesn't create new line.
var doc = app.activeDocument;
// get a text from the XLSX file
var inputFile = File("~/Desktop/test.xlsx");
var temp_frame = doc.textFrames.add();
temp_frame.place(inputFile);
var text = temp_frame.parentStory.contents;
temp_frame.remove();
// make a table from the text
text = text.split('\r');
var table = [];
for (var row = 1; row < text.length; row++) {
table.push(text[row].split('\t'));
}
// loop through the table and make the cards
for (var i = 0; i < table.length; i++) {
var title = table[i][0];
var description = table[i][1];
var price = table[i][2];
var card = make_card(title, description, price);
// move card to some place
card.move([10,10]);
card.move(undefined, [i*75, 0]);
if(i > 2){
card.move([20,10]);
card.move(undefined, [i*75, 20]);
}
}
// the function to create and return a card
function make_card(title, description, price) {
var doc = app.activeDocument;
var title_frame = doc.textFrames.add();
title_frame.geometricBounds = [20, 80, 30, 150];
title_frame.contents = title;
var description_frame = doc.textFrames.add();
description_frame.geometricBounds = [30, 80, 80, 150];
description_frame.contents = description;
var price_frame = doc.textFrames.add();
price_frame.geometricBounds = [80, 80, 100, 150];
price_frame.contents = price;
var group = doc.groups.add([title_frame, description_frame, price_frame]);
return group;
}
My question is how to write code that card doesn't go out of the document but follow on next line and as well as how to add new page automatically when current document is already full.
I tried do do it with following code in loop if index is heigher than 2 move card down. It move it down but it follow in the same line (out of the document) and I also think there is better way how to write it because if excel has 1000 rors and I have to set up this if index condition for every third element ... code will be one mash
if(i > 2){
card.move([20,10]);
card.move(undefined, [i*75, 20]);
}
For this case the simplest straightforward implementation could be like this:
var doc = app.activeDocument;
// get a text from the XLSX file
var inputFile = File("~/Desktop/test.xlsx");
var temp_frame = doc.textFrames.add();
temp_frame.place(inputFile);
var text = temp_frame.parentStory.contents;
temp_frame.remove();
// make a table from the text
var rows = text.split('\r');
var table = [];
for (var i = 1; i < rows.length; i++) table.push(rows[i].split('\t'));
// width and height of cards, gaps, properties of the grid
var card_width = 70;
var card_height = 80;
var gap = 5;
var cols = 2;
var rows = 3;
var cards_per_page = cols * rows;
// calculate and add pages
var cards = table.length;
var pages_to_add = Math.ceil(cards / cards_per_page) - 1;
while(pages_to_add--) doc.pages.add();
var page_num = 0; // start page
var start_point = [10,10]; // start point for a first card on a page
main_loop:
for (var i = 0; i < cards; i++) {
for (var row = 0; row < rows; row++) {
for (var col = 0; col < cols; col++) {
// break the loop if there is no more rows in the table
if (table.length == 0) break main_loop;
var table_row = table.shift(); // take a first row from the table
var title = table_row[0];
var description = table_row[1];
var price = table_row[2];
// make a card
var card = make_card(title, description, price);
// send the card to the some page and move at some place
card.move(doc.pages[page_num]);
card.move(start_point);
card.move(undefined, [(card_width + gap)*col, (card_height + gap)*row]);
}
}
if (i > (page_num-1) * cards_per_page) page_num++; // increase the page number
}
// the function to create and return a card
function make_card(title, description, price) {
var doc = app.activeDocument;
var title_frame = doc.textFrames.add();
title_frame.geometricBounds = [20, 80, 30, 150];
title_frame.contents = title;
var description_frame = doc.textFrames.add();
description_frame.geometricBounds = [30, 80, 80, 150];
description_frame.contents = description;
var price_frame = doc.textFrames.add();
price_frame.geometricBounds = [80, 80, 100, 150];
price_frame.contents = price;
var group = doc.groups.add([title_frame, description_frame, price_frame]);
return group;
}

How to download Carbon monoxide concentration daily data from Google Earth Engine, without gaps?

I need to download Carbon monoxide concentrations daily data provided by sentinel 5p but the data consists of gaps for my region of interest
var dataset1 = ee.ImageCollection("COPERNICUS/S5P/NRTI/L3_CO")
.filterDate('2021-03-01', '2021-03-31')
.filterBounds(roi)
.select("CO_column_number_density")
print (dataset1)
var img = dataset1.filterMetadata('TIME_REFERENCE_DAYS_SINCE_1950', 'equals',25992 )
.mean();
Map.addLayer(img)
Google Earth Engine
This is the code used. I am trying to average the data available for a single day but there are gaps. if the data has to be averaged over more than one day, how to do it? how to create a loop that iterates over the dates and computes the average?
Try This Code
var batch = require('users/fitoprincipe/geetools:batch')
print("batch.help", batch.help)
var Sentinel_CO_Dataset = ee.ImageCollection("COPERNICUS/S5P/NRTI/L3_CO")
.filterDate('2021-03-01', '2021-03-10')
.filterBounds(roi)
.select("CO_column_number_density")
print (Sentinel_CO_Dataset)
var count = Sentinel_CO_Dataset.size()
print("Collection count", count)
var all_Sentinel_CO_tiles = Sentinel_CO_Dataset.map(function(image) { return image.clip(roi).reproject('EPSG:4326', null, 1113.2); });
var check = ee.Image(all_Sentinel_CO_tiles.first());
var Sentinel_CO_Palette = ['FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718',
'74A901', '66A000', '529400', '3E8601', '207401', '056201',
'004C00', '023B01', '012E01', '011D01', '011301'];
Map.addLayer(check, {min:0.02, max: 0.05, palette: Sentinel_CO_Palette}, 'Sentinel_CO_Palette_Check');
var colList = all_Sentinel_CO_tiles.toList(all_Sentinel_CO_tiles.size());
var n = colList.size().getInfo();
for (var i = 0; i < n; i++) {
var img = ee.Image(colList.get(i));
var id = img.id().getInfo();
var listOfImages = all_Sentinel_CO_tiles.toList(all_Sentinel_CO_tiles.size());
var Tile = listOfImages.get(i);
var allRasters = ee.ImageCollection.fromImages([Tile]);
batch.Download.ImageCollection.toDrive(allRasters, "Sentinel_CO",
{name: 'MONOXIDE_'+id,
scale: 1113.2,
region: roi
})
}

Google Form creates Google Slides from template Script

I have a script that on Form submit takes the data from the spreadsheet and creates a copy of a template and populates the google docs. I am trying to accomplish the same thing from google form to google slides.
First script I use for the google forms to google docs. The second script is my attempt of using the same principles and applying to google slides. My issue is I'm getting an error saying TypeError: values.forEach is not a function (line 109, file "Code") in relation to values.forEach(function(page). Any suggestions on how I could go about solving this?
Google Form to Google Sheets
function autoFillGoogleDocFromForm(e) {
var timestamp = e.values[0];
var address = e.values[1];
var image = e.values[2];
var price = e.values[3];
var summary = e.values[4];
var type = e.values[5];
var year_built = e.values[6];
var bed = e.values[7];
var bath = e.values[8];
var home_size = e.values[9];
var lot_size = e.values[10];
var occupancy = e.values[11];
var templateFile = DriveApp.getFileById("xxxxxxxx");
var templateResponseFolder = DriveApp.getFolderById("yyyyyyyyyy")
var copy = templateFile.makeCopy( address , templateResponseFolder);
var doc = DocumentApp.openById(copy.getId())
var body = doc.getBody();
body.replaceText("{{address}}", address);
body.replaceText("{{price}}", price);
body.replaceText("{{summary}}", summary);
body.replaceText("{{type}}", type);
body.replaceText("{{year_built}}", year_built);
body.replaceText("{{beds}}", bed);
body.replaceText("{{baths}}", bath);
body.replaceText("{{home_size}}", home_size);
body.replaceText("{{lot_size}}", lot_size);
body.replaceText("{{occupancy}}", occupancy);
doc.saveAndClose;
}
Google Form to Google Slides
function generateLandingPagesReport(){
var dataSpreadsheetUrl = "https://docs.google.com/spreadsheets/xxxxxxxxx/edit"
var Presentation_ID = "xxxxxxxxxxxxxx";
var ss = SpreadsheetApp.openByUrl(dataSpreadsheetUrl);
var deck = SlidesApp.openById(Presentation_ID);
var sheet = ss.getSheetByName('Sheet1');
var values = sheet.getRange('A1:J17').getValues;
var slides = deck.getSlides();
var templateSlide = slides[1];
var presLength = slides.length;
values.forEach(function(page){
values.forEach(function(page){
if(page[0]){
var landingPage = page[0];
var sessions = page[1];
var newSessions = page[2];
}
templateSlide.duplicate(); // duplicate the template page
/*slides = deck.getSlides(); // update the slides array for indexes and length*/
newSlide = slides[2]; // declare the new page to update
var shapes = (newSlide.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{landing page}}', landingPage);
shape.getText().replaceAllText('{{sessions}}', sessions);
shape.getText().replaceAllText('{{new sessions}}',newSessions);
});
presLength = slides.length;
newSlide.move(presLength);
//end our condition statement
}); //close our loop of values
//remove template slide
templateSlide.remove();
});
}
You're missing the parenthesis when calling the getValue() method.
Change this:
var values = sheet.getRange('A1:J17').getValues;
To this:
var values = sheet.getRange('A1:J17').getValues();
Not exactly what I was looking for but this uses the first Row to identify the tag inside the Google slides template like {{title}} and replaces that with the value in the second row of the sheet
function createPresentation() {
var templateFile = DriveApp.getFileById("1YVEA4WtU1Kf6nZRgHpwnKBIR-V6rRN6s9zCdOQDkWNI");
var templateResponseFolder = DriveApp.getFolderById("1k7rcfXODij4o4arSULuKZUHbit1m_X64");
var copy = templateFile.makeCopy("New" , templateResponseFolder);
var Presentation = SlidesApp.openById(copy.getId());
var values = SpreadsheetApp.getActive().getDataRange().getValues();
values.forEach(function(row) {
var templateVariable = row[0];
var templateValue = row[1];
Presentation.replaceAllText(templateVariable, templateValue);
});
}
After you have copy the template page, you work on it and try to do replace.
However, change may be pending such that newSlide = slides[2]; give undefined.
You may need to try saveAndClose() before performing any actions.
templateSlide.duplicate(); // duplicate the template page
/*slides = deck.getSlides(); // update the slides array for indexes and length*/
/* flush the presentation */
deck.saveAndClose();
deck = SlidesApp.openById(Presentation_ID);
slides = deck.getSlides();
newSlide = slides[2]; // declare the new page to update
var shapes = (newSlide.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{landing page}}', landingPage);
shape.getText().replaceAllText('{{sessions}}', sessions);
shape.getText().replaceAllText('{{new sessions}}',newSessions);
});

How to optimize Google Apps Script Code to prevent maximum execution time exceeded?

This Google Apps Script Project takes photos from a Google Drive folder and uses these photos to create a slideshow. Basically, it takes the file name as the student's name, the file as the picture to be inserted into the slideshow, and it also puts the school logo and Grad ${{Current Year}}. I want this script to be able to deal with thousands of photos if possible without exceeding the quota.
Is there a way to optimize this code so it only runs for 1 to 2 mins and be able to deal with 1000 or more photos.
function createPresentation() {
var year, school, name, fileName, colour, foreground, font, nameSize, titleSize, gradSize, schoolLogo, deck;
year = new Date().getFullYear().toString(); // Current Year
school = 'High School'; // School Name
name = "Class of " + year;
fileName = "Class of " + year + " - " + school; // Class Year
colour = "#C53023"; // School Colour
foreground = "#000000"; // Foreground Colour (Black)
font = "Roboto"; // Font
nameSize = 70; // Font size for names
titleSize = 80; // Font size for title
gradSize = 33; // Font size for Grad 20..
schoolLogo = '.../logo.jpg'; // School Logo
deck = SlidesApp.create(fileName); // Creates the presentation
title(deck, font, name, colour, school, foreground, titleSize );
createSlides(deck, schoolLogo, year, gradSize, font);
createStudents(deck);
}
function title(deck, font, name, colour, school, fcolour, fsize ){
var [title, subtitle] = deck.getSlides()[0].getPageElements();
// Class of ${Current Year}
title.asShape().getText().setText(name);
title.asShape().getText().getTextStyle().setBold(true).setForegroundColor(colour).setFontSize(fsize).setFontFamily(font);
// School Name
subtitle.asShape().getText().setText(school);
subtitle.asShape().getText().getTextStyle().setBold(true).setFontFamily(font).setForegroundColor(fcolour).setFontSize(33);
}
function countFiles() {
// Function to count the number of files in the folder
var files = DriveApp.getFoldersByName("Test").next().getFiles();
var count = 0;
while (files.hasNext()){
count++;
file = files.next();
}
return count;
}
function measureImage(){
}
function createSlides(deck, logoURL, year, fontSize, font) {
// Function to create slides
var numSlides = parseInt(countFiles()); // Number of files in Graduation folder
for (var i = 0; i < numSlides; i++) {
slide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
var logo = slide.insertImage(logoURL).setTop(322).setLeft(50).setHeight(60).setWidth(80);
var caption = 'GRAD' + " " + year;
var shape = slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, 149, 324, 260, 90);
var textRange = shape.getText();
textRange.setText(caption).getTextStyle().setFontSize(fontSize).setFontFamily(font).setBold(true);
}
}
function createStudents(deck){
// Get names and pictures from file
var count = 1;
// Student Names
var folder = "Test" // Folder Name
var files = DriveApp.getFoldersByName(folder).next().getFiles(); // Get files from folder
while (files.hasNext()){
var file = files.next();
var slide = deck.getSlides()[count]
// Get and format students' name from file name.
var studentName = file.getName();
var studentf = studentName.split('.').slice(0, -1).join('.')
var fields = studentf.split('_');
var firstname = fields[1] ;
var lastname = fields[0];
// Place the name on the slide
var shape = slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, 50, 80, 320, 120);
var textRange = shape.getText();
textRange.setText(firstname + '\n' + lastname).getTextStyle().setFontSize(60).setFontFamily('Roboto').setBold(false).setForegroundColor('#C53023');
var paragraphs = textRange.getParagraphs();
for (var i = 0; i < 2; i++) {
var paragraphStyle = paragraphs[i].getRange().getParagraphStyle();
paragraphStyle.setParagraphAlignment(SlidesApp.ParagraphAlignment.CENTER);
}
// Get the image and set its location.
var image = slide.insertImage(file.getAs('image/png'));
var imgWidth = image.getWidth();
var imgHeight = image.getHeight();
var pageWidth = deck.getPageWidth();
var pageHeight = deck.getPageHeight();
var newX = pageWidth/2. - imgWidth/2.;
var newY = pageHeight/2. - imgHeight/2.;
image.setLeft(newX+200).setTop(newY);
count++;
}
}
Every time the script runs, it gets timed out after ~366 seconds (~6.1 mins).

More than 1 instance of annotation not working in Acrobat

I'm trying to add multiple annotations in pdf document through Acrobat javascript. However, only the first annotation is working if I include both. The second annotation only works if I include that one separately.
var spans = new Array();
spans[0] = new Object();
spans[0].text = "Links to: ";
spans[0].textSize = 12;
spans[0].textColor = color.red;
spans[1] = new Object();
spans[1].text = "http://www.example.com";
spans[1].textSize = 12;
spans[1].textColor = color.black;
// Now create the annot with spans as it's richContents
var annot = this.addAnnot({
page: 0,
type: "FreeText",
rect: [50, 50, 300, 100],
richContents: spans
});
var copy_annot = this.addAnnot({type: "Line"})
annot.setProps({
page: 0,
points: [[400,490],[430,690]],
strokeColor: color.red,
arrowBegin: "Diamond",
arrowEnd: "OpenArrow"
});
I had forgotten to change the variable name before setting the property
Solution:
var copy_annot = this.addAnnot({type: "Line"})
copy_annot.setProps({
...
});

Categories

Resources