Apps 脚本:使用来自 Google Sheet 的数据行填充模板。如何让它更有活力?

Apps Script: Fill template with rows of data from Google Sheet. HOW to make it more dynamic?

我有一个脚本,它用 Google Sheet 中每一行的数据替换 Google 文档模板中的每个 {{Keyword}}。 (下面的示例 sheet)

Name Address City Document Link
Name 1 Address 1 City 1 the script writes the new doc URL here
Name 2 Address 2 City 2 the script writes the new doc URL here

这是我目前运行(成功)的代码:

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('Documents & Mail Merge')
      .addItem('Generate Documents', 'createNewGoogleDocs')
      .addSeparator()
      .addToUi();
}

function createNewGoogleDocs() {
      const documentLink_Col = ("Document Link");
      const template = DriveApp.getFileById('templateIdGoesHere');
      const destinationFolder = DriveApp.getFolderById('destinationFolderIdGoesHere');
      const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data');
      const data = sheet.getDataRange().getDisplayValues();
      const heads = data[0]; // Assumes row 1 contains the column headings
      const documentLink_ColIndex = heads.indexOf(documentLink_Col);

data.forEach(function(row, index){
      if(index === 0 || row[documentLink_ColIndex]) return;
      const templateCopy = template.makeCopy(`${row[0]} ${row[1]} Report`, destinationFolder); //create a copy of the template document
      const templateCopyId = DocumentApp.openById(templateCopy.getId());
      const templateCopyBody = templateCopyId.getBody();
          templateCopyBody.replaceText('{{Name}}', row[0]);
          templateCopyBody.replaceText('{{Address}}', row[1]);
          templateCopyBody.replaceText('{{City}}', row[2]);
          templateCopyId.saveAndClose();
      const url = templateCopyId.getUrl();
          sheet.getRange(index +1 , documentLink_ColIndex + 1).setValue(url);
})
}

我想实现的功能/更改的功能: 将硬编码的 {{Placeholders}}(例如 templateCopyBody.replaceText('{{Name}}', row[0]);)替换为另一种将任何列名视为模板文档中潜在 {{Placeholder}} 的方法。 所以基本上 我应该可以自由地编辑、添加、移动或删除 sheet 中的列,而不必再对它们进行硬编码,而只是调整模板。

可能有帮助,我发现了一种类似的脚本,它使用 Gmail 草稿作为模板而不是 Google 文档,根据我的理解,这里有 2 个函数可以实现我需要的功能:

  /**
   * Fill template string with data object
   * @see 
   * @param {string} template string containing {{}} markers which are replaced with data
   * @param {object} data object used to replace {{}} markers
   * @return {object} message replaced with data
  */
  function fillInTemplateFromObject_(template, data) {
    // We have two templates one for plain text and the html body
    // Stringifing the object means we can do a global replace
    let template_string = JSON.stringify(template);

    // Token replacement
    template_string = template_string.replace(/{{[^{}]+}}/g, key => {
      return escapeData_(data[key.replace(/[{}]+/g, "")] || "");
    });
    return  JSON.parse(template_string);
  }

  /**
   * Escape cell data to make JSON safe
   * @see 
   * @param {string} str to escape JSON special characters from
   * @return {string} escaped string
  */
  function escapeData_(str) {
    return str
      .replace(/[\]/g, '\\')
      .replace(/[\"]/g, '\\"')
      .replace(/[\/]/g, '\/')
      .replace(/[\b]/g, '\b')
      .replace(/[\f]/g, '\f')
      .replace(/[\n]/g, '\n')
      .replace(/[\r]/g, '\r')
      .replace(/[\t]/g, '\t');
  };
}

虽然我是一个完全的菜鸟,但我无法在原始 createNewGoogleDocs 函数内的 foreach 循环中成功调用 fillInTemplateFromObject_ 函数,这就是我的假设我应该怎么做?

对于由于缺乏经验而可能出现的选词不当之处,我们深表歉意,并在此先感谢大家的支持。

你的情况,下面的修改怎么样?

修改后的脚本:

请设置模板文档 ID 和文件夹 ID。

function createNewGoogleDocs() {
  const documentLink_Col = "Document Link";
  const template = DriveApp.getFileById('templateIdGoesHere');
  const destinationFolder = DriveApp.getFolderById('destinationFolderIdGoesHere');
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data');
  const [header, ...values] = sheet.getDataRange().getDisplayValues();
  const documentLink_ColIndex = header.indexOf(documentLink_Col);
  const data = values.map(r => {
    const temp = r.reduce((o, c, j) => {
      o[header[j]] = c;
      return o;
    }, {});
    return { filename: `${r[0]} ${r[1]} Report`, obj: temp };
  });
  const v = data.map(({ filename, obj }) => {
    if (obj[documentLink_Col]) return [obj[documentLink_Col]];
    const templateCopy = template.makeCopy(filename, destinationFolder); //create a copy of the template document
    const templateCopyId = DocumentApp.openById(templateCopy.getId());
    const templateCopyBody = templateCopyId.getBody();
    Object.entries(obj).forEach(([k, v]) => templateCopyBody.replaceText(`{{${k}}}`, v));
    templateCopyId.saveAndClose();
    const url = templateCopyId.getUrl();
    return [url];
  });
  sheet.getRange(2, documentLink_ColIndex + 1, v.length, 1).setValues(v);
}
  • 在此修改中,创建了包含 header 和值的 object。使用这个object,动态使用占位符。并且,在创建文档后,将 URL 放入 Document Link.

    列中
  • 例如,当你更改电子表格的header值和模板文档的占位符时,可以使用此脚本。

参考文献: