Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)

目標

每逢過年過節,不時會收到些禮物或送出些禮物,但要怎麼樣依據不同的對象,來客製化我們的內容。尤其當超過百人要送禮時,又要怎麼簡單快速地做出文件?這時可以考慮用 GAS 搭配 Google Sheet 與 Goolge Doc。那,就讓我們看看如何「只調整 Google Doc 中的一點點部分」?

  1. 要如何自動依照範本創造並微調 Google 文件(Google Docs)?

今天只有一個問題,昨天我們回答了如何簡單客製化,今天我們會用「複雜範本」當案例,那就讓我們就開始吧!


Q1. 要如何自動依照範本創造並微調 Google 文件(Docs)?

今天我們的情境是,要大量產生給客戶的內容;像是我們最近要準備中秋的禮品們,請問要怎麼自動化大型的標籤?可以用 Google Sheet 拉,但如果想要大一點,用半張紙來排版,能怎麼做?

Step 1 開啟 Google Sheet,並串起 GAS

好,那因為我們要用到 Google Sheet ,所以一樣用其作為開啟的管道。一樣借用 D8 的影片。

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图

一樣執行時會有「需要驗證」出現,借用一下 D2 的影片。

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图1

Step 2 設定要作為 Template 的 Google Docs ID

關於創造文件,我們可以選擇複製範本(像是 D11),或是創造新的文件(像是 D12);昨天我們講解了「創造新文件」,這篇會針對「複製範本」來做介紹。那現在一樣抓起範本的 ID,而以下是我們抓 ID 的兩種方式——

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图2

每一個 Google 產品都有特定的 ID,可以用我們上述的方式簡單取得,如果想複習,在 D9 有完整的介紹可以參考。

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图3

那我們做一個範本如下——

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图4

有看到收件者、地址與電話嗎?我這邊直接用一個變數代稱,分別是 receiver、address 和 phone number,晚點這三個變數都用到。

將範本的 ID 抓出。

var template_doc_id= "your_id_here"

完整取得 ID 的方式在 D9 有詳細的介紹可參考:如何用 Google Apps Script 自動化對 Google Drive 的操作?(一)列出所有檔案 ID 與相關資訊

Step 3 複製範本複製並調整

那我們要怎麼做到複製範本並調整呢?

要先提到的是 Google Doc 中主要分成兩大物件,一個是 Element,主要就是文字、影像、段落、表格等等的「純內容」、骨架。一個是 Attribute,包含字體大小、排版、顏色、粗斜體等等,是 Element 的外皮、外衣與皮膚 。(概念上,有點像是 html element 和 css style )。今天我們會主要講 ElementType 的部分

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图5

這邊先用一段程式碼示範給大家看。

function createDocFromTemplate(){
  let row_data = ['101','Amy','經理','0911111111','','House of Amy']
  let doc_file = DriveApp.getFileById(template_ID);
  let title = row_data[0] + " " + row_data[1] + " " + row_data[2];
  let contact = '';
  let new_doc_Id = doc_file.makeCopy(title).getId()
  let new_doc = DocumentApp.openById(new_doc_Id);
  let doc_body = new_doc.getBody();

  if (row_data[3]){
    contact= row_data[3]
  }else{
    contact= row_data[4]
  }

  Logger.log(title+ " "+ contact+ " "+ row_data[5])
  doc_body.replaceText("receiver", title);
  doc_body.replaceText("address", row_data[5]);
  doc_body.replaceText("phone number", contact);
}

這段程式碼的意思是——

  1. 我先寫一個預計會收到的資料 ['101','Amy','經理','0911111111','','House of Amy']
  2. 並將 Title 設定為前三個字串加在一起,以此為例就是 101 Amy 經理
  3. 用 Title 其作為檔案的名稱,注意這邊我是針對前面 file Object 用 .makeCopy(title) 的,如果對 Drive 不熟,可以參考 D8。
  4. 同時取得其 ID 後,再用 DocumentApp.openById 改成以 Document Object 操作。並用其抓出 body() 這邊跟昨天的 D14 一樣。
  5. 接著這段說明一下,因為原本的名單可能有兩種電話,一種是手機號碼 row_data[3],一種是市話 row_data[4],一種是沒號碼。我寫了一段 for 迴圈,用意是想說當有手機的話,聯絡資訊就留手機,沒手機就留市話(是話與手機都沒有的話,會填預設的市話 (row_data[4] ==””),也就是空白的字串。
  6. 最後,我用 replaceText 來取代掉 Template 裡面的文字。

第六小點我多說明一些。我們使用的是 body Object 的 method,完整的寫法是 replaceText(searchPattern, replacement) 

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图6
  • 前面要放(要被取代的)pattern ,實際上是 regex 的表示法,如果不熟悉,可以當成「變數」來想像。 但實際上功能很強大,可以搜尋特字元。好,那同時在範本設定變數中,要小心設定,別設定文中可能有的文字,不然在沒有設定好 Pattern 的情況下會一起被更換。
  • 後面要放(要用來取代的)replacement 內容。基本上就是文字

我們來看跑出來的結果——

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图7

好,那看起來沒問題,那我們要怎麼大量執行。

Step 4 針對每一份資料複製並調整

那我們要長出什麼樣子呢?這邊先給大家看我們今天的參數。

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图8

接下來的步驟是:

  1. 取得資料
  2. 將一筆筆的資料與 Step 3 結合

一樣,先來看看完整程式碼。

var template_ID = "your_doc_template_id_here";

// 從 Google Sheet 的 B2 開取到 G7
function readSheetData(){
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getActiveSheet();
  let start_row = 2;
  let start_col = 2;
  let numRows = sheet.getLastRow() - start_row +1;
  let numCols = sheet.getLastColumn() - start_col +1;;
  let values = sheet.getRange(start_row,start_col,numRows,numCols).getValues();
  return values;
}

// 轉接「讀變數」與「寫文件」
function writePages(){
  let data = readSheetData();
  for (row_data of data){
    createDocFromTemplate(row_data);
  }
}

// 微調的「寫文件」功能
function createDocFromTemplate(row_data){
  let doc_file = DriveApp.getFileById(template_ID);
  let title = row_data[0] + " " + row_data[1] + " " + row_data[2];
  let contact = '';
  let new_doc_Id = doc_file.makeCopy(title).getId()
  let new_doc = DocumentApp.openById(new_doc_Id);
  let doc_body = new_doc.getBody();

  if (row_data[3]){
    contact= row_data[3]
  }else{
    contact= row_data[4]
  }

  Logger.log(title+ " "+ contact+ " "+ row_data[5])
  doc_body.replaceText("receiver", title);
  doc_body.replaceText("address", row_data[5]);
  doc_body.replaceText("phone number", contact);
}

取得資料部分,如果不懂為什麼有這樣的架構、要這樣寫,可以參考 D4;寫資料部分,則就單純是把上面的 Step 3 改一下。

最後跑出來長這樣——

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图9

好,那今天就完成了!事後有朋友問,那如果想要將很多檔案合併起來怎麼辦?不想要這麼分散。

Step 5

這邊就直接做給大家看。簡單來說,我們創造一份新文件(DocumentApp.create()),然後把每一份從 Template 複製的內容(template_file.getBody().copy())改完後丟回原本的新文件,再加上分頁 (appendPageBreak())。

function moveFile(fileId, destinationFolderId) {
  let destinationFolder = DriveApp.getFolderById(destinationFolderId);
  DriveApp.getFileById(fileId).moveTo(destinationFolder);
}

function writePages(){
  let data = readSheetData();
  let new_doc_Id = DocumentApp.create("all_docs").getId();
  moveFile(new_doc_Id,folder_ID);
  let template_file = DocumentApp.openById(template_ID);
  let new_doc = DocumentApp.openById(new_doc_Id);
  for (row_data of data){
    mergeDocFromTemplate(row_data, new_doc, template_file);
    new_doc.appendPageBreak();
  };
}

function mergeDocFromTemplate(row_data, new_doc,template_file){
  let title = row_data[0] + " " + row_data[1] + " " + row_data[2];
  let contact = '';
  let copied_body = template_file.getBody().copy();


  if (row_data[3]){
    contact= row_data[3]
  }else{
    contact= row_data[4]
  }

  Logger.log(title+ " "+ contact+ " "+ row_data[5])
  copied_body.replaceText("receiver", title);
  copied_body.replaceText("address", row_data[5]);
  copied_body.replaceText("phone number", contact);

  let totalElements = copied_body.getNumChildren();
  for( let j = 0; j < totalElements; ++j ) {
      let element = copied_body.getChild(j).copy();
      new_doc.appendParagraph(element);
  }
}

那跑起來長這樣——

Google Apps Script 自動化地創造與客製 Google Docs(二)快速生出大量寄件信封資料 (2021 鐵人賽 D15)插图10

比較特別要提的是,Google Docs 裡面每一個段落、文字、影像等都是一個物件,這也是為何我們會需要先透過 .getNumChildren() 來抓出要複製的內容,再一個個的用 appendParagraph() 貼上。提醒的是,所謂 paragraph 對 word 來說,是按下一次 enter 就會算創造一個新的段落。

我們這邊用的 appendParagraph() 是「僅限文字段落」的複製,如果要複製影像、Table、List 等其他格式等,可以參考這篇來實作: How to Merge Multiple Google Documents


今天的主題是為了應景中秋節看夥伴很辛苦地用名單,順手寫出來的。想說就趕緊先上應用版,明天再上完整辭典版。

一樣提醒的是,創造文件有 Quota 限制——每天不超過 250 件。好,那今天就是我們的 D15,明天我會介紹要怎麼樣操作更多的 Element。

如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。

目錄

Scroll to Top