使用 Google 脚本创建和/或更新邮件合并 Google 文档

Posted

技术标签:

【中文标题】使用 Google 脚本创建和/或更新邮件合并 Google 文档【英文标题】:Creating and/or update mail merge Google document using Google Script 【发布时间】:2021-03-11 21:21:16 【问题描述】:

(Continuation of another thread)

我目前有一个 Google 表格,其中包含要使用模板文件合并到 Google 文档中的数据行。每行都将根据模板的布局生成一个新的 Google 文档。我当前正在运行的脚本将检查是否已经存在与 Google 表格行相关的文件(使用标题单元格进行匹配)。如果是这样,那么它将被删除,并在其位置创建一个新文档,其中包含在 Google 表格中所做的所有更改。如果它不存在,将创建一个新文档。

但是,我现在需要从外部网站链接到这些 Google 文档。使用当前脚本,这意味着如果对电子表格中的一行进行了更改,则相应的文档将被删除并重新创建,连同它的 URL,从而使网站链接无用,需要手动更改。

因此,理想情况下,我想要实现的不是删除和重新创建文档,而是更新同一个文档(如果它已经存在)。这样,文档会得到更新,并且 URL 将始终保持不变。

目前的脚本是这样的

    /*###################################################################
 * Create multiple versions of a document based on Google Sheet Data
 * and a Google Doc Template (Mailmerge)
 *###################################################################
 */

/*###################################################################
 * Main run file sets up variables for insertion into the mailMerge() 
 * function. 
 */
function mergeSheetDoc() 
  const TEMPLATE_ID = '16YfyeDjGDp-88McAtLCQQyZ1xz4QX5zEKAS09SaLkJI';//Add your Google Doc template ID
  const SS_ID = '1C5gtJCSzHMuSz-oVWEItl2EUVRDwF5iH_RVr6BxLkOU'; // Add your Google Sheet ID
  const SHEET_NAME = "data"; // Add your Google Sheet Tab name
  const MAPPED = mappedDocToSheet; // Go to Map.gs to update
  const FILE_NAME = ["Titre de la formation"] // Header IDs from your Sheet. Change to make your own file name.
  
  docMerge(TEMPLATE_ID,SS_ID,SHEET_NAME,MAPPED, FILE_NAME);



/** ###################################################################
 * Merges data from a Google Sheet into a newly created doc based on a 
 * Google Doc template. 
 * 
 * param string templateID: The id from the Google Doc template. 
 * param string ssID: The id of the Google Sheet. 
 * param string sheetName: the name of the sheet tab you are referencing.
 * param object mapped: Object array of data you mapped from your Doc template against your Google Sheet headers
 * param array fileNameDara: An array of data used to generate the file name. 
 * param string rowLen: (optional) If you want to add a number rows to create your merged documents.  
 */ 
function docMerge(templateID,ssID, sheetName, mapped, fileNameData, rowLen = "auto")
  //Get the Spreadsheet and sheet tab
  const ss = SpreadsheetApp.openById(ssID);
  const sheet = ss.getSheetByName(sheetName);
  
  //Get number of rows to process
  rowLen = (rowLen = "auto") ? getRowLen() : rowLen;
  
  //Gets the range of data in the sheet then grabs the values of the range
  const range = sheet.getRange(1,1,rowLen,sheet.getDataRange().getNumColumns());
  const matrix = range.getValues();
  
  // Searches the file mapped object and finds the corresponding number returns the column number in an array.
  const fileNameRows = getFileNameRows()
  
  
  //Loops through each row of the sheet grabbing the data from each row and putting it into a new doc.
  for(let i = 1; i < rowLen; i++)
    let row = matrix[i];
    //Get the title for the file.
    let fileName = buildFileName(row);
   
    //This query parameter will search for an exact match of the filename with Doc file type
  let params = "title='"+fileName+"' and mimeType = 'application/vnd.google-apps.document'"
    let files = DriveApp.searchFiles(params);

    if(files.hasNext())
      while (files.hasNext()) 
        //Filename exist
        var file = files.next();


        //Create a new file
        var tmpDoc = DriveApp.getFileById(templateID).makeCopy("tempfile");
        //Update the file
        updateFileData(row, tmpDoc.getId());

        //Copy contents of the new file to the existing file
        copyFileData(tmpDoc.getId(), file.getId());

        //Delete temporary file
        tmpDoc.setTrashed(true);
      
    else
      //Create a new file
      let newDoc = DriveApp.getFileById(templateID).makeCopy(fileName);
    
      updateFileData(row, newDoc.getId());
    
  
  
;

  function copyFileData(sourceDoc, destinationDoc)
   var srcParagraph = DocumentApp.openById(sourceDoc).getBody().getParagraphs();
   var dstParagraph = DocumentApp.openById(destinationDoc).getBody().getParagraphs();
   
   for(var i = 0; i<dstParagraph.length; i++)

      //Paragraph Index of description and suivantes information
      if(i==5||i==21)
        
        dstParagraph[i].editAsText().setText(srcParagraph[i].editAsText().getText());
        dstParagraph[i].setAttributes(srcParagraph[i].getAttributes());
        dstParagraph[i].setLeftToRight(true);
        dstParagraph[i].setIndentFirstLine(srcParagraph[i].getIndentFirstLine());
        dstParagraph[i].setIndentStart(srcParagraph[i].getIndentStart());
        dstParagraph[i].editAsText().setFontSize(srcParagraph[i].editAsText().getFontSize());

      
   
 

此代码还引用了一个映射脚本,可在此处找到

https://textuploader.com/18xic

【问题讨论】:

【参考方案1】:

解决方法总结:

如果文件名已经存在,则创建一个临时文档,用于替换模板文档中的 textId 标签 将临时文档的段落文本和属性复制到现有文档中。

示例修改代码:

仅包含修改/新功能。

function docMerge(templateID,ssID, sheetName, mapped, fileNameData, rowLen = "auto")
  //Get the Spreadsheet and sheet tab
  const ss = SpreadsheetApp.openById(ssID);
  const sheet = ss.getSheetByName(sheetName);
  
  //Get number of rows to process
  rowLen = (rowLen = "auto") ? getRowLen() : rowLen;
  
  //Gets the range of data in the sheet then grabs the values of the range
  const range = sheet.getRange(1,1,rowLen,sheet.getDataRange().getNumColumns());
  const matrix = range.getValues();
  
  // Searches the file mapped object and finds the corresponding number returns the column number in an array.
  const fileNameRows = getFileNameRows()
  
  
  //Loops through each row of the sheet grabbing the data from each row and putting it into a new doc.
  for(let i = 1; i < rowLen; i++)
    let row = matrix[i];
    //Get the title for the file.
    let fileName = buildFileName(row);
   
    //This query parameter will search for an exact match of the filename with Doc file type
  let params = "title='"+fileName+"' and mimeType = 'application/vnd.google-apps.document'"
    let files = DriveApp.searchFiles(params);

    if(files.hasNext())
      while (files.hasNext()) 
        //Filename exist
        var file = files.next();


        //Create a new file
        var tmpDoc = DriveApp.getFileById(templateID).makeCopy("tempfile");
        //Update the file
        updateFileData(row, tmpDoc.getId());

        //Copy contents of the new file to the existing file
        copyFileData(tmpDoc.getId(), file.getId());

        //Delete temporary file
        tmpDoc.setTrashed(true);
      
    else
      //Create a new file
      let newDoc = DriveApp.getFileById(templateID).makeCopy(fileName);
    
      updateFileData(row, newDoc.getId());
    
  
  ;
 
 function copyFileData(sourceDoc, destinationDoc)
   var srcParagraph = DocumentApp.openById(sourceDoc).getBody().getParagraphs();
   var dstParagraph = DocumentApp.openById(destinationDoc).getBody().getParagraphs();
   
   for(var i = 0; i<dstParagraph.length; i++)

      //Paragraph Index of description and suivantes information
      if(i==5||i==21)
        
        dstParagraph[i].editAsText().setText(srcParagraph[i].editAsText().getText());
        dstParagraph[i].setAttributes(srcParagraph[i].getAttributes());
        dstParagraph[i].setLeftToRight(true);
        dstParagraph[i].setIndentFirstLine(srcParagraph[i].getIndentFirstLine());
        dstParagraph[i].setIndentStart(srcParagraph[i].getIndentStart());
        dstParagraph[i].editAsText().setFontSize(srcParagraph[i].editAsText().getFontSize());

      
   
 

它有什么作用?

    如果找到文件名,请根据电子表格中的更新信息创建一个临时文档 将临时文档中的特定段落复制到现有文档中 使用setTrashed()方法删除临时文档。

【讨论】:

我似乎遇到了 docMerge 或 mergeSheetDoc 的以下错误“ReferenceError: getRowLen is not defined”。我已经修改了我的初始帖子以显示脚本我的结束 你需要包括你所有的功能,我没有把完整的代码放在答案中。我刚刚修改了 docMerge() 并定义了一个新函数 copyFileData() 我明白了,我可以看到它在工作,这太棒了。我现在将测试多行并进行测试,以便它为新行创建文档 注意,如果您遇到任何其他问题,请告诉我 似乎为新行创建新文档并使用更新的内容更新现有文档。它完全按照我的需要工作。再次感谢你。我非常感激。很高兴看到它工作。赞成并接受回答:)

以上是关于使用 Google 脚本创建和/或更新邮件合并 Google 文档的主要内容,如果未能解决你的问题,请参考以下文章

Google网络应用/脚本,用于自动将文件上传到特定的g-drive文件夹

尝试使用Google表格脚本将表格图表插入到电子邮件草稿中

如何使用 Google Apps 脚本将 PDF 正文格式化为看起来像电子邮件?

发送个性化的Google应用脚本电子邮件导致我的电子邮件被禁用

关于如何使用从其电子表格的html表单接收的数据创建pdf并通过电子邮件发送pdf文件的Google应用程序脚本

Google表格合并的单元格创建空间