iT邦幫忙

2021 iThome 鐵人賽

DAY 15
0
Modern Web

整合 Google 服務的燃料——透過 Google Apps Script (GAS) 加速你的工作速度系列 第 15

D15 - 如何用 Apps Script 自動化地創造與客製 Google Docs?(二)快速生出大量寄件信封資料

  • 分享至 

  • xImage
  •  

今天的目標

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

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

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


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

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

Step 1 開啟 Google Sheet,並串起 GAS

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

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

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

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

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

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

有看到收件者、地址與電話嗎?我這邊直接用一個變數代稱,分別是 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 的部分

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

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)

  • 前面要放(要被取代的)pattern ,實際上是 regex 的表示法,如果不熟悉,可以當成「變數」來想像。 但實際上功能很強大,可以搜尋特字元。好,那同時在範本設定變數中,要小心設定,別設定文中可能有的文字,不然在沒有設定好 Pattern 的情況下會一起被更換。
  • 後面要放(要用來取代的)replacement 內容。基本上就是文字

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

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

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

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

接下來的步驟是:

  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 改一下。

最後跑出來長這樣——

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

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

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


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

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

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


上一篇
D14 - 如何用 Apps Script 自動化地創造與客製 Google Docs?(一) 以 NDA 為例的大架構與簡單複製
下一篇
D16 - 如何用 Apps Script 自動化地創造與客製 Google Docs?(三)Element 的讀取與創造
系列文
整合 Google 服務的燃料——透過 Google Apps Script (GAS) 加速你的工作速度30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言