Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)

目標

要怎麼簡單快速地做出客製化地文件?今天,我們會教用 GAS 搭配 Goolge Doc。那因為在 Google Slide 中的 Element 也是相同的,所以這邊就會講細一點,之後就可以一起飲用。換句話說,今天會教說怎麼透過 GAS 調整 Google Doc 和 Google Slide 裡面的元素。那今天的問題可以有以下的排列組合——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图

雖然總共有 4×4 共 16 種的排列組合,我們會用案例一個個來說明。基本上昨天講了講新增與讀取,今天會專注於刪除,就讓我們開始吧!

先來個小測驗

請問下圖的問號裡,可以填入什麼?
Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图1
再來問大家兩題是非題,提示:getNumChildren()可以幫助取得接下來一層有的物件。
Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图2

答案在今天的文章當中!

前情提要一下

考慮到有些夥伴不一定會都看過前面的文章,就撈叨一點把基本步驟再次附上,如果會的夥伴可以直接跳到 Q1。

我們已經知道大致上,每一個 Google 文件都會有 Element (元件),且每一個 Element 都會有 Attribute (屬性)。今天我們主要會介紹藍色的 Element 的部分。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图3

那我們把 Element 展開來看,裡面有很多小的物件,這邊抓出其中最常用的四種。分別是段落、照片、表格與清單。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图4

那我們的目標就是透過讀取、寫入、更新與刪除(對的,參照 CRUD 的 format)來帶大家讓是怎麼操作這些表格。這邊就節錄一本書中的「段落、照片、表格與清單」,來作為今天我們的範例。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图5

那在開始前,先來個重要的概念——

物件間的親子關係(Parent / Child)

我們確實可以透過 getImages()getTables() 來取得幾個比較重要的物件們。當我們想進入更細節的物件取得時,像是細節到 Table 的哪一格時,就會需要知道他們之間的親子關係,或是說上下層關係。

這邊我們要介紹一個觀念叫 Parent() 和 Children(),基本上我們可以透過 getParent() 和 getChildren() 來取得上下層關係的物件。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图6

但,唯獨 Document 的物件例外,當我們用 let doc = DocumentApp.getActiveDocument(); 取得 doc 物件時,它既沒有上層的 parent(用 getParent() 會得到 null),更沒辦法直接取得 children()(沒有 getChildren() 的方式)。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图7

簡單來說,就是你想看到 Document 下層。需要明明白白地指派是要 Header、Body 還是 Footer。

那另外一間值得注意的事是, Child_index 會是每個物件就會算一次。所以當我們看這位在第一頁的三個表單時,他會出現的 ChildIndex 並不是 1, 2, 3。那會是什麼呢?

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图8

而是 1, 4, 7,為什麼呢?因為在我們表單的前面有著「換行」剛剛有提到,「每個物件就算一次」,那當然就包括段落(Paragraph),而昨天我們有提到,空白段落(換行)也是一個 Object。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图9

而更重要的是,我們說 parent 和 child 可以幫我們來取得有上下層關係的物件。那 Table 下面也有下層的 TableRow, TableRow 則還有更下層的 TableCell。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图10

好,那到目前為止的概念,應該是能夠幫你回答最前面那兩題的。這邊也公布參考答案——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图11

那 Parent 和 Child 的概念很重要,因為回到我們的目的,當我們要「部分」刪除或更新時,它就會派上用場。也附上這段檢查用的程式碼——

function readChild(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  let tables = doc_body.getTables();
  for (let i=0;i<tables.length;i++){
    Logger.log(doc_body.getChildIndex(tables[i]))
    Logger.log(tables[i].getNumChildren())
    Logger.log(tables[i].getChild(0).getChild(0))
  }
}

好,理解這邊的概念後,再來進入實作囉!

Step 1 從 Document 中進入 GAS

那這次我們不會用 Google Sheet,而是直接用 Google Doc 進入。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图12

一樣第一次會有存取驗證需要大家按一下。這邊仍是借用一下 D2 的影片。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图13

Step 2 設定好 getBody()

我們先用 getActiveDocument() 抓出正在綁定的文件;那假設我們都是針對主要內文(Body)的部分,所以我們先設定好 getbody()

let doc_body = DocumentApp.getActiveDocument().getBody();

完整的架構概念,可以參考 Google 的官方文件

因為更新有比較複雜的細節,我們就先來講講刪除。

Q3. 如何刪除 Google Docs 中的表格

刪除之前基本上要先取得,所以先讓我們取得表格。這邊我加入一些假表格。

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图14

接著,我們要讀取表格,並進行刪除。

Step 3 讀取要刪除的部分

然後接下來要先用昨天的 read 來進行讀取。

function readTables(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  let tables = doc_body.getTables();
  for (let i=0;i<tables.length;i++){
    Logger.log(tables[i].getText())
  }
}

來確認一下跑起來如何——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图15

好,看來有抓到範圍。

Step 4-1 用 clear() 刪除整張表單

如果要將整個文件全部刪除,程式碼很簡單——

function clearDoc(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  doc_body.clear();
}

跑起來長這樣——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图16

如果是要銜接 Step 3,將表格刪除,那要怎麼做?我們來示範只刪掉後面兩個。因為 Tables 回傳會是三個 Table 的 Objects,理論上 Tables 是長這樣 [Table obj 1, Table obj 2, Table obj 3] ,而因為是 Array 的形式,我們要取的條件是 table[i] 中 i > 0 的情況。。

function deleteTables(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  let tables = doc_body.getTables();
  for (let i=0;i<tables.length;i++){
    if(i > 0){
      tables[i].clear()
	}
  }
}

跑起來長這樣——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图17

好,那這就是刪除整個表格的做法。但如果有的時候,我們只是要針對部分內容進行刪除,又要怎麼做?這邊就要用我們最一開始的 Children 的概念了。

Step 4-1 刪除部分的表單

假設我想刪掉第一列,那該怎麼辦?我們有提到,因為 table 下面是以 tableRow 作為下層物件,我們可以直接用 table.getChild 來進行刪除。而因為 Table Row 之間不會有其他空白段落,所以可以直接指派特定的那列。

舉例來說,我想將全部表格的「第ㄧ列」刪除。

function deleteSecondRow(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  let tables = doc_body.getTables();
  for (let i=0;i<tables.length;i++){
    tables[i].getChild(0).clear()
  }
}

跑起來長這樣——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图18

要注意的是,我對 tables[i] 的 getChild(index) 中的 index 輸入的是 0,因為這邊不是 Google Sheet,要回程式語言的以 0 為基準點。

那如果,我想將右下角的 Cell 刪除呢?

function deleteBottomRightCell(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  let tables = doc_body.getTables();
  for (let i=0;i<tables.length;i++){
    tables[i].getChild(1).getChild(1).clear();
  }
}

跑起來長這樣——

Google Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係 (2021 鐵人賽 D17)插图19

值得注意的是,現在 Google Doc 不支援非長方形的表格了,所以用 Clear() 只會清除到裡面的值。換句話說,如果今天你不想刪掉列,而是列裡面的特定值的話,可以寫成——

function deleteRowValue(){
  let doc_body = DocumentApp.getActiveDocument().getBody();
  let tables = doc_body.getTables();
  for (let i=0;i<tables.length;i++){
  	for (let j=0;j<tables.getChild(0).getNumChildren;i++){
  	tables[i].getChild(1).getChild(j).clear();
  }
}

好,那如果今天我想要將第二直欄的表格刪掉,該怎麼辦?以目前 Google Docs 的架構,我們會需要創造另外一個表單,這另外找時間寫。那因為表單是最複雜的,其他相對清單、照片與段落,基本上都是透過 Clear() 就可以刪除,瞭解完表單後,理論上其他的實作就不會那麼難。

好,那今天就到這邊。

結論

好,那今天我們主要交代了 Parent/Child 和如何刪除,篇幅關係,更新我們留到明天分享;如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。

目錄

Scroll to Top