iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Modern Web

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

D17 - 如何用 Apps Script 自動化地創造與客製 Google Docs?(四)Element 的刪除與層級關係

  • 分享至 

  • xImage
  •  

今天的目標

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

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

先來個小測驗。

請問下圖的問號裡,可以填入什麼?

再來問大家兩題是非題,提示:getNumChildren()可以幫助取得接下來一層有的物件。

答案在今天的文章當中!

前情提要一下

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

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

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

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

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

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

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

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

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

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

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

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

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

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

那 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 進入。

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

Step 2 設定好 getBody()

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

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

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

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

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

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

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

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())
  }
}

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

好,看來有抓到範圍。

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

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

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

跑起來長這樣——

如果是要銜接 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()
	}
  }
}

跑起來長這樣——

好,那這就是刪除整個表格的做法。但如果有的時候,我們只是要針對部分內容進行刪除,又要怎麼做?這邊就要用我們最一開始的 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()
  }
}

跑起來長這樣——

要注意的是,我對 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 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。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。


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

尚未有邦友留言

立即登入留言