タブの操作

Google Docs API を使用すると、ドキュメントの任意のタブからコンテンツにアクセスできます。

タブとは

Google ドキュメントには、タブと呼ばれる組織レイヤがあります。Google ドキュメントでは、現在の Google スプレッドシートのタブと同様に、1 つのドキュメント内に複数のタブを作成できます。各タブには、独自のタイトルと ID(URL に追加)があります。タブには子タブを設定することもできます。子タブは、別のタブの下にネストされたタブです。

ドキュメント コンテンツがドキュメント リソースでどのように表現されるかの構造的な変更

以前のドキュメントにはタブの概念がなかったため、Document リソースには次のフィールドを通じてすべてのテキスト コンテンツが直接含まれていました。

タブの構造階層が追加されたため、これらのフィールドはドキュメント内のすべてのタブのテキスト コンテンツを意味的に表さなくなりました。テキストベースのコンテンツは別のレイヤで表現されるようになりました。Google ドキュメントのタブのプロパティとコンテンツには、document.tabs を使用してアクセスできます。これは Tab オブジェクトのリストで、各オブジェクトには前述のテキスト コンテンツ フィールドがすべて含まれています。以降のセクションでは概要を説明します。タブの JSON 表現でも詳細な情報を提供しています。

[Access] タブのプロパティ

tab.tabProperties を使用してタブのプロパティにアクセスします。これには、タブの ID、タイトル、位置などの情報が含まれます。

タブ内のテキスト コンテンツにアクセスする

タブ内の実際のドキュメント コンテンツは tab.documentTab として公開されます。前述のテキスト コンテンツ フィールドはすべて、tab.documentTab を使用してアクセスできます。たとえば、document.body ではなく document.tabs[indexOfTab].documentTab.body を使用する必要があります。

タブの階層

子タブは、API では Tabtab.childTabs フィールドとして表されます。ドキュメント内のすべてのタブにアクセスするには、子タブの「ツリー」をたどる必要があります。たとえば、次のようなタブ階層を含むドキュメントについて考えてみましょう。

3 つの最上位タブを含むタブリスト UI。一部のタブには子タブがあります

Tab 3.1.2 から Body を取得するには、document.tabs[2].childTabs[0].childTabs[1].documentTab.body にアクセスします。後述のサンプルコード ブロックを参照してください。このブロックには、ドキュメント内のすべてのタブを反復処理するサンプルコードが用意されています。

メソッドの変更

タブの導入に伴い、各ドキュメント メソッドにいくつかの変更が加えられました。コードの更新が必要になる場合があります。

documents.get

デフォルトでは、すべてのタブの内容が返されるわけではありません。すべてのタブにアクセスするには、コードを更新する必要があります。documents.get メソッドは、すべてのタブのコンテンツをレスポンスで提供するかどうかを構成できる includeTabsContent パラメータを公開します。

  • includeTabsContenttrue に設定されている場合、documents.get メソッドは document.tabs フィールドが入力された Document リソースを返します。document に直接あるテキスト フィールド(document.body など)はすべて空のままになります。
  • includeTabsContent が指定されていない場合、Document リソースのテキスト フィールド(document.body など)には、最初のタブのコンテンツのみが入力されます。document.tabs フィールドは空になり、他のタブのコンテンツは返されません。

documents.create

documents.create メソッドは、作成された空のドキュメントを表す Document リソースを返します。返された Document リソースは、ドキュメントのテキスト コンテンツ フィールドと document.tabs の両方で、空のドキュメント コンテンツを設定します。

document.batchUpdate

Request には、更新を適用するタブを指定する方法が含まれています。デフォルトでは、タブが指定されていない場合、ほとんどの場合、Request はドキュメントの最初のタブに適用されます。ReplaceAllTextRequestDeleteNamedRangeRequestReplaceNamedRangeContentRequest は 3 つの特別なリクエストで、デフォルトではすべてのタブに適用されます。

詳しくは、Request のドキュメントをご覧ください。

ドキュメント内のタブ、ブックマーク、見出しへの内部リンクを作成できます。タブ機能の導入により、Link リソースの link.bookmarkId フィールドと link.headingId フィールドは、ドキュメント内の特定のタブのブックマークや見出しを表すことができなくなりました。

デベロッパーは、読み取りオペレーションと書き込みオペレーションで link.bookmarklink.heading を使用するようにコードを更新する必要があります。内部リンクは BookmarkLink オブジェクトと HeadingLink オブジェクトを使用して公開されます。各オブジェクトには、ブックマークまたは見出しの ID と、それが配置されているタブの ID が含まれています。また、link.tabId はタブへの内部リンクを公開します。

documents.get レスポンスのリンクの内容は、includeTabsContent パラメータによっても異なります。

  • includeTabsContenttrue に設定されている場合、すべての内部リンクが link.bookmarklink.heading として公開されます。以前のフィールドは使用されなくなります。
  • includeTabsContent が指定されていない場合、単一のタブを含むドキュメントでは、その単一のタブ内のブックマークまたは見出しへの内部リンクは引き続き link.bookmarkId および link.headingId として公開されます。複数のタブを含むドキュメントでは、内部リンクは link.bookmarklink.heading として公開されます。

document.batchUpdate で、以前のフィールドのいずれかを使用して内部リンクが作成された場合、ブックマークまたは見出しは Request で指定されたタブ ID からのものとみなされます。タブが指定されていない場合は、ドキュメントの最初のタブからとみなされます。

リンクの JSON 表現には、より詳細な情報が記載されています。

タブの一般的な使用パターン

次のコードサンプルは、タブを操作するさまざまな方法を示しています。

ドキュメント内のすべてのタブからタブの内容を読み取る

タブ機能の前にこれを行っていた既存のコードは、includeTabsContent パラメータを true に設定し、タブツリー階層をトラバースし、Document の代わりに TabDocumentTab からゲッター メソッドを呼び出すことで、タブをサポートするように移行できます。次のコードサンプルの一部は、ドキュメントからテキストを抽出するのスニペットに基づいています。ドキュメントのすべてのタブのテキスト コンテンツを印刷する方法を示します。このタブ トラバーサル コードは、タブの実際の構造を気にしない他の多くのユースケースに適用できます。

Java

/** Prints all text contents from all tabs in the document. */
static void printAllText(Docs service, String documentId) throws IOException {
  // Fetch the document with all of the tabs populated, including any nested
  // child tabs.
  Document doc =
      service.documents().get(documentId).setIncludeTabsContent(true).execute();
  List<Tab> allTabs = getAllTabs(doc);

  // Print the content from each tab in the document.
  for (Tab tab: allTabs) {
    // Get the DocumentTab from the generic Tab.
    DocumentTab documentTab = tab.getDocumentTab();
    System.out.println(
        readStructuralElements(documentTab.getBody().getContent()));
  }
}

/**
 * Returns a flat list of all tabs in the document in the order they would
 * appear in the UI (top-down ordering). Includes all child tabs.
 */
private List<Tab> getAllTabs(Document doc) {
  List<Tab> allTabs = new ArrayList<>();
  // Iterate over all tabs and recursively add any child tabs to generate a
  // flat list of Tabs.
  for (Tab tab: doc.getTabs()) {
    addCurrentAndChildTabs(tab, allTabs);
  }
  return allTabs;
}

/**
 * Adds the provided tab to the list of all tabs, and recurses through and
 * adds all child tabs.
 */
private void addCurrentAndChildTabs(Tab tab, List<Tab> allTabs) {
  allTabs.add(tab);
  for (Tab tab: tab.getChildTabs()) {
    addCurrentAndChildTabs(tab, allTabs);
  }
}

/**
 * Recurses through a list of Structural Elements to read a document's text
 * where text may be in nested elements.
 *
 * <p>For a code sample, see
 * <a href="https://developers.google.com/workspace/docs/api/samples/extract-text">Extract
 * the text from a document</a>.
 */
private static String readStructuralElements(List<StructuralElement> elements) {
  ...
}

ドキュメントの最初のタブからタブの内容を読み取る

これは、すべてのタブを読み取るのと同様の操作です。

Java

/** Prints all text contents from the first tab in the document. */
static void printAllText(Docs service, String documentId) throws IOException {
  // Fetch the document with all of the tabs populated, including any nested
  // child tabs.
  Document doc =
      service.documents().get(documentId).setIncludeTabsContent(true).execute();
  List<Tab> allTabs = getAllTabs(doc);

  // Print the content from the first tab in the document.
  Tab firstTab = allTabs.get(0);
  // Get the DocumentTab from the generic Tab.
  DocumentTab documentTab = firstTab.getDocumentTab();
  System.out.println(
      readStructuralElements(documentTab.getBody().getContent()));
}

最初のタブを更新するリクエストを作成する

次のコードサンプルの一部は、Request で特定のタブをターゲットにする方法を示しています。このコードは、テキストの挿入、削除、移動ガイドのサンプルに基づいています。

Java

/** Inserts text into the first tab of the document. */
static void insertTextInFirstTab(Docs service, String documentId)
    throws IOException {
  // Get the first tab's ID.
  Document doc =
      service.documents().get(documentId).setIncludeTabsContent(true).execute();
  Tab firstTab = doc.getTabs().get(0);
  String tabId = firstTab.getTabProperties().getTabId();

  List<Request>requests = new ArrayList<>();
  requests.add(new Request().setInsertText(
      new InsertTextRequest().setText(text).setLocation(new Location()
                                                            // Set the tab ID.
                                                            .setTabId(tabId)
                                                            .setIndex(25))));

  BatchUpdateDocumentRequest body =
      new BatchUpdateDocumentRequest().setRequests(requests);
  BatchUpdateDocumentResponse response =
      docsService.documents().batchUpdate(DOCUMENT_ID, body).execute();
}