Работа с вкладками

API Документов Google позволяет получать доступ к контенту с любой вкладки документа.

Что такое вкладки?

В Документах Google есть организационный уровень, называемый вкладками . Документы позволяют пользователям создавать одну или несколько вкладок в одном документе, подобно тому, как сегодня существуют вкладки в Таблицах. Каждая вкладка имеет свой заголовок и идентификатор (добавляется в URL-адрес). Вкладка также может иметь дочерние вкладки — вкладки, вложенные под другую вкладку.

Поддержка API для дочерних вкладок доступна уже сегодня, но поддержка пользовательского интерфейса появится в ближайшее время. Вы можете обрабатывать дочерние вкладки в своем коде уже сегодня, чтобы при запуске поддержки пользовательского интерфейса вам не приходилось вносить дальнейшие обновления кода.

Структурные изменения в представлении содержимого документа в ресурсе документа.

Раньше в документах не было концепции вкладок, поэтому ресурс Document напрямую содержал все текстовое содержимое через следующие поля:

  • document.body
  • document.headers
  • document.footers
  • document.footnotes
  • document.documentStyle
  • document.suggestedDocumentStyleChanges
  • document.namedStyles
  • document.suggestedNamedStylesChanges
  • document.lists
  • document.namedRanges
  • document.inlineObjects
  • document.positionedObjects

Благодаря дополнительной структурной иерархии вкладок эти поля больше не представляют семантически текстовое содержимое всех вкладок в документе. Текстовый контент теперь представлен на другом слое. Свойства и содержимое вкладок в Документах Google доступны с помощью documents.tabs , который представляет собой список Tabs , каждая из которых содержит все вышеупомянутые поля текстового содержимого. В последующих разделах дается краткий обзор; Представление Tab JSON также предоставляет более подробную информацию.

Доступ к свойствам вкладки

Доступ к свойствам вкладки осуществляется с помощью tab.tabProperties , который включает в себя такую ​​информацию, как идентификатор, заголовок и расположение вкладки.

Доступ к текстовому содержимому на вкладке

Фактическое содержимое документа на вкладке отображается как tab.documentTab . Все вышеупомянутые поля текстового содержимого доступны с помощью tab.documentTab . Например, вместо использования document.body вам следует использовать document.tabs[indexOfTab].documentTab.body .

Иерархия вкладок

Дочерние вкладки представлены в API как поле tab.childTabs на Tab . Доступ ко всем вкладкам в документе требует обхода «дерева» дочерних вкладок. Например, рассмотрим документ, содержащий следующую иерархию вкладок:

Пользовательский интерфейс списка таблиц, содержащий три вкладки верхнего уровня, некоторые из которых имеют дочерние вкладки.

Чтобы получить body из вкладки 3.1.2 , вам нужно получить доступ к document.tabs[2].childTabs[0].childTabs[1].documentTab.body . См. примеры блоков кода в следующем разделе, где представлен пример кода для перебора всех вкладок в документе.

Изменения в методах

С появлением вкладок каждый из методов документа претерпел некоторые изменения, которые могут потребовать обновления кода.

документы.получить

По умолчанию возвращается не все содержимое вкладки. Разработчикам следует обновить свой код, чтобы получить доступ ко всем вкладкам. Метод documents.get предоставляет параметр includeTabsContent , который позволяет настроить, будет ли в ответе отображаться содержимое всех вкладок.

  • Если includeTabsContent установлено значение true , метод documents.get вернет ресурс Document с заполненным полем document.tabs . Все текстовые поля непосредственно в document (например, document.body ) останутся пустыми.
  • Если includeTabsContent не указан, то текстовые поля в ресурсе Document (например, document.body ) будут заполнены содержимым только первой вкладки. Поле document.tabs будет пустым, и содержимое других вкладок не будет возвращено.

документы.создать

Метод documents.create возвращает ресурс Document , представляющий созданный пустой документ. Возвращенный ресурс Document заполнит пустое содержимое документа как в полях текстового содержимого документа, так и document.tabs .

документ.batchUpdate

Каждый Request включает в себя способ указать вкладки, к которым будет применено обновление. По умолчанию, если вкладка не указана, Request в большинстве случаев будет применен к первой вкладке в документе. ReplaceAllTextRequest , DeleteNamedRangeRequest и ReplaceNamedRangeContentRequest — это три специальных запроса, которые вместо этого по умолчанию применяются ко всем вкладкам.

Более подробную информацию можно найти в документации Request .

Пользователи могут создавать внутренние ссылки на вкладки, закладки и заголовки в документе. С появлением функции вкладок поля link.bookmarkId и link.headingId больше не могут представлять закладку или заголовок на определенной вкладке документа.

Разработчикам следует обновить свой код, чтобы использовать link.bookmark и link.heading в операциях чтения и записи. Они предоставляют внутренние ссылки с помощью объектов BookmarkLink и HeadingLink , каждый из которых содержит идентификатор закладки или заголовка и идентификатор вкладки, на которой они расположены. Кроме того, link.tabId предоставляет внутренние ссылки на вкладки.

Содержимое ссылки в ответе documents.get также может различаться в зависимости от параметра includeTabsContent :

  • Если includeTabsContent установлено значение true , все внутренние ссылки будут отображаться как link.bookmark и link.heading . Устаревшие поля ( link.bookmarkId и link.headingId ) больше не будут использоваться.
  • Если includeTabsContent не указан, то в документах, содержащих одну вкладку, любые внутренние ссылки на закладки или заголовки внутри этой отдельной вкладки продолжают отображаться как link.bookmarkId и link.headingId . В документах, содержащих несколько вкладок, внутренние ссылки будут отображаться как link.bookmark и link.heading .

В document.batchUpdate , если внутренняя ссылка создается с использованием одного из устаревших полей, закладка или заголовок будут считаться взятыми из идентификатора вкладки, указанного в Request . Если вкладка не указана, она будет считаться первой вкладкой в ​​документе.

Представление Link JSON предоставляет более подробную информацию.

Общие шаблоны использования вкладок

Следующие примеры кода описывают различные способы взаимодействия с вкладками.

Чтение содержимого вкладок со всех вкладок в документе.

Существующий код, который делал это до функции вкладок, можно перенести для поддержки вкладок, установив для параметра IncludeTabsContent значение true , пройдя по иерархии дерева вкладок и вызвав методы получения из Tab и DocumentTab вместо Document . Следующий пример частичного кода основан на фрагменте Извлечь текст из документа . Он показывает, как распечатать все текстовое содержимое каждой вкладки документа. Этот код обхода вкладок можно адаптировать для многих других случаев использования, в которых не важна фактическая структура вкладок.

Джава

/** 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) {
  ...
}

Чтение содержимого вкладки с первой вкладки документа.

Это похоже на чтение всех вкладок.

Джава

/** 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 . Этот код основан на образце из руководства по вставке, удалению и перемещению текста .

Джава

/** 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();
}