タブの操作

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

タブとは

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

ドキュメント リソース内でドキュメント コンテンツが表現される方法の構造的な変更

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

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

タブのプロパティにアクセスする

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

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

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

タブの階層

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

3 つの最上位タブ(一部に子タブがあるもの)を含むタブリスト UI

タブ 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.bookmarkIdlink.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/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();
}