Como trabalhar com guias

A API Documentos Google permite acessar conteúdo de qualquer guia no documento.

O que são guias?

Os Documentos Google têm uma camada organizacional chamada guias. O app Documentos permite que os usuários criem uma ou mais guias em um único documento, semelhante às guias das Planilhas. Cada guia tem o próprio título e ID (anexados ao URL). Uma guia também pode ter guias filhas, que são guias aninhadas abaixo de outra guia.

Mudanças estruturais na representação do conteúdo do documento no recurso de documento

No passado, os documentos não tinham o conceito de guias. Portanto, o recurso Document continha diretamente todo o conteúdo de texto nos seguintes campos:

Com a hierarquia estrutural adicional das guias, esses campos não representam mais semanticamente o conteúdo de texto de todas as guias no documento. O conteúdo baseado em texto agora é representado em uma camada diferente. As propriedades e o conteúdo das guias nos Documentos Google podem ser acessados com document.tabs, que é uma lista de objetos Tab, cada um dos quais contém todos os campos de conteúdo de texto mencionados. As seções a seguir oferecem uma breve visão geral. A representação JSON da guia também fornece informações mais detalhadas.

Acessar propriedades da guia

Acesse as propriedades da guia usando tab.tabProperties, que inclui informações como o ID, o título e a posição da guia.

Acessar o conteúdo de texto em uma guia

O conteúdo do documento na guia é exposto como tab.documentTab. Todos os campos de conteúdo de texto mencionados acima podem ser acessados usando tab.documentTab. Por exemplo, em vez de usar document.body, use document.tabs[indexOfTab].documentTab.body.

Hierarquia de guias

As guias filhas são representadas na API como um campo tab.childTabs em Tab. Para acessar todas as guias em um documento, é necessário percorrer a "árvore" de guias filhas. Por exemplo, considere um documento que contém uma hierarquia de guias da seguinte maneira:

Interface da lista de guias com três guias de nível superior, algumas delas com guias filhas

Para extrair o Body da guia 3.1.2, acesse document.tabs[2].childTabs[0].childTabs[1].documentTab.body. Consulte os blocos de código de exemplo na seção posterior, que fornece um exemplo de código para iterar em todas as guias de um documento.

Mudanças em métodos

Com a introdução das guias, cada um dos métodos de documento tem algumas mudanças que podem exigir a atualização do código.

documents.get

Por padrão, nem todo o conteúdo da guia é retornado. Os desenvolvedores precisam atualizar o código para acessar todas as guias. O método documents.get expõe um parâmetro includeTabsContent que permite configurar se o conteúdo de todas as guias é fornecido na resposta.

  • Se includeTabsContent for definido como true, o método documents.get vai retornar um recurso Document com o campo document.tabs preenchido. Todos os campos de texto diretamente em document (por exemplo, document.body) serão deixados vazios.
  • Se includeTabsContent não for fornecido, os campos de texto no recurso Document (por exemplo, document.body) serão preenchidos com o conteúdo da primeira guia. O campo document.tabs vai estar vazio, e o conteúdo de outras guias não será retornado.

documents.create

O método documents.create retorna um recurso Document que representa o documento vazio que foi criado. O recurso Document retornado vai preencher o conteúdo vazio do documento nos campos de conteúdo de texto do documento e document.tabs.

document.batchUpdate

Cada Request inclui uma maneira de especificar as guias em que a atualização será aplicada. Por padrão, se uma guia não for especificada, o Request será aplicado, na maioria dos casos, à primeira guia do documento. ReplaceAllTextRequest, DeleteNamedRangeRequest e ReplaceNamedRangeContentRequest são três solicitações especiais que serão aplicadas por padrão a todas as guias.

Consulte a documentação do Request para saber mais detalhes.

Os usuários podem criar links internos para guias, favoritos e títulos em um documento. Com a introdução do recurso de guias, os campos link.bookmarkId e link.headingId no recurso Link não podem mais representar um marcador ou título em uma guia específica do documento.

Os desenvolvedores precisam atualizar o código para usar link.bookmark e link.heading em operações de leitura e gravação. Eles expõem links internos usando objetos BookmarkLink e HeadingLink, cada um contendo o ID do marcador ou título e o ID da guia em que ele está localizado. Além disso, link.tabId expõe links internos para guias.

O conteúdo do link de uma resposta documents.get também pode variar dependendo do parâmetro includeTabsContent:

  • Se includeTabsContent estiver definido como true, todos os links internos serão expostos como link.bookmark e link.heading. Os campos legados não serão mais usados.
  • Se includeTabsContent não for fornecido, em documentos que contêm uma única guia, todos os links internos para favoritos ou títulos nessa guia vão continuar sendo expostos como link.bookmarkId e link.headingId. Em documentos com várias guias, os links internos são expostos como link.bookmark e link.heading.

No document.batchUpdate, se um link interno for criado usando um dos campos legados, a marcação ou o título será considerado do ID da guia especificado no Request. Se nenhuma guia for especificada, ela será considerada da primeira guia no documento.

A representação JSON do link fornece informações mais detalhadas.

Padrões de uso comuns para guias

Os exemplos de código abaixo descrevem várias maneiras de interagir com as guias.

Ler o conteúdo de todas as guias no documento

O código existente que fez isso antes que o recurso de guias pudesse ser migrado para oferecer suporte a guias definindo o parâmetro includeTabsContent como true, percorrendo a hierarquia de guias e chamando métodos de getter de Tab e DocumentTab em vez de Document. O exemplo de código parcial a seguir é baseado no snippet em Extrair o texto de um documento. Ele mostra como imprimir todo o conteúdo de texto de cada guia em um documento. Esse código de navegação de guias pode ser adaptado para muitos outros casos de uso que não se importam com a estrutura real das guias.

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

Ler o conteúdo da primeira guia do documento

Isso é semelhante a ler todas as guias.

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

Faça uma solicitação para atualizar a primeira guia

O exemplo de código parcial a seguir mostra como segmentar uma guia específica em um Request. Esse código é baseado no exemplo do guia Inserir, excluir e mover texto.

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