Mesclar texto em um documento

Este guia explica como usar a API Google Docs para mesclar informações de uma ou mais fontes de dados externas em um documento de modelo existente.

Um modelo é um tipo de documento que contém texto fixo e marcadores de posição para conteúdo dinâmico. Por exemplo, um modelo de contrato pode conter texto fixo com marcadores de posição para o nome e o endereço do destinatário. Em seguida, o app mescla dados específicos do usuário no modelo para criar o documento final.

Há vários motivos para essa abordagem ser útil:

  • Os designers podem ajustar o design de um documento usando o Google Docs. Isso é mais simples do que ajustar parâmetros no app para definir o layout renderizado.

  • Separar o conteúdo da apresentação é um princípio de design conhecido com muitos benefícios.

Diagrama mostrando como os dados de uma fonte são mesclados em um modelo para criar um documento.
Figura 1. Mesclar dados em um modelo para criar um documento.

Como funciona uma mesclagem de documentos

Confira um exemplo de como usar a API Docs para mesclar dados em um documento:

  1. Crie o documento usando conteúdo de marcador de posição para ajudar no design e no formato. Toda a formatação de texto que você quiser substituir será preservada.

  2. Para cada elemento que você inserir, substitua o conteúdo do marcador de posição por uma tag. Use strings que provavelmente não ocorram normalmente. Por exemplo, {{account-holder-name}} pode ser uma boa tag.

  3. No código, use a API Google Drive para fazer uma cópia do documento.

  4. No código, use o método batchUpdate da API Docs com o nome do documento e inclua um ReplaceAllTextRequest.

Os IDs de documentos fazem referência a um documento e podem ser derivados do URL:

https://docs.google.com/document/d/DOCUMENT_ID/edit

Gerenciar modelos

Para documentos de modelo que o app define e possui, crie o modelo usando uma conta dedicada que representa o app. Contas de serviço são uma boa opção e evitam complicações com as políticas do Google Workspace que restringem o compartilhamento.

Ao criar instâncias de documentos com base em modelos, sempre use credenciais de usuário final. Isso oferece aos usuários controle total sobre o documento resultante e evita problemas de escalonamento relacionados a limites por usuário no Google Drive.

Para criar um modelo usando uma conta de serviço, siga estas etapas com as credenciais do app:

  1. Crie um documento usando documents.create na API Docs.
  2. Atualize as permissões para permitir que os destinatários do documento leiam usando permissions.create na API Drive.
  3. Atualize as permissões para permitir que os autores do modelo gravem nele usando permissions.create na API Drive.
  4. Edite o modelo conforme necessário.

Para criar uma instância do documento, siga estas etapas com as credenciais do usuário:

  1. Crie uma cópia do modelo usando files.copy na API Drive.
  2. Substitua os valores usando documents.batchUpdate na API Docs.

Exemplo: mesclar dados em um modelo

O exemplo de código a seguir mostra como substituir dois campos em todas as guias de um modelo por valores reais para gerar um documento final:

Imagem mostrando um modelo de documento com marcadores de posição de tag e o documento mesclado resultante.
Figura 2. Substituir marcadores de posição de tag por valores.

Para realizar essa mesclagem, use o código a seguir:

Java

String customerName = "Alice";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String date = formatter.format(LocalDate.now());

// Make a copy of the template document using the Drive API.
String copyTitle = "Merged Document";
File copyMetadata = new File().setName(copyTitle);
File documentCopyFile =
        driveService.files().copy(DOCUMENT_ID, copyMetadata).execute();
String documentCopyId = documentCopyFile.getId();

List requests = new ArrayList<>();
// One option for replacing all text is to specify all tab IDs.
requests.add(new Request()
        .setReplaceAllText(new ReplaceAllTextRequest()
                .setContainsText(new SubstringMatchCriteria()
                        .setText("{{customer-name}}")
                        .setMatchCase(true))
                .setReplaceText(customerName)
                .setTabsCriteria(new TabsCriteria()
                        .addTabIds(TAB_ID_1)
                        .addTabIds(TAB_ID_2)
                        .addTabIds(TAB_ID_3))));
// Another option is to omit TabsCriteria if you are replacing across all tabs.
requests.add(new Request()
        .setReplaceAllText(new ReplaceAllTextRequest()
                .setContainsText(new SubstringMatchCriteria()
                        .setText("{{date}}")
                        .setMatchCase(true))
                .setReplaceText(date)));

BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest();
service.documents().batchUpdate(documentCopyId, body.setRequests(requests)).execute();

Node.js

  let customerName = 'Alice';
  let date = yyyymmdd()
  let requests = [
    // One option for replacing all text is to specify all tab IDs.
    {
      replaceAllText: {
        containsText: {
          text: '{{customer-name}}',
          matchCase: true,
        },
        replaceText: customerName,
        tabsCriteria: {
          tabIds: [TAB_ID_1, TAB_ID_2, TAB_ID_3],
        },
      },
    },
    // Another option is to omit TabsCriteria if you are replacing across all tabs.
    {
      replaceAllText: {
        containsText: {
          text: '{{date}}',
          matchCase: true,
        },
        replaceText: date,
      },
    },
  ];

  // Make a copy of the template document using the Drive API.
  let copyTitle = 'Merged Document';
  driveService.files.copy({
    fileId: '1yBx6HSnu_gbV2sk1nChJOFo_g3AizBhr-PpkyKAwcTg',
    resource: {
      name: copyTitle,
    },
  }, (err, driveResponse) => {
    if (err) return console.log('The Drive API returned an error: ' + err);
    let documentCopyId = driveResponse.data.id;

    google.options({auth: auth});
    google
        .discoverAPI(
            'https://docs.googleapis.com/$discovery/rest?version=v1&key={YOUR_API_KEY}')
        .then(function(docs) {
          docs.documents.batchUpdate(
              {
                documentId: documentCopyId,
                resource: {
                  requests,
                },
              },
              (err, {data}) => {
                if (err) return console.log('The API returned an error: ' + err);
                console.log(data);
              });
        });
  });

Python

customer_name = 'Alice'
date = datetime.datetime.now().strftime("%y/%m/%d")

# Make a copy of the template document using the Drive API.
copy_title = 'Merged Document'
body = {
    'name': copy_title
}
drive_response = drive_service.files().copy(
    fileId=DOCUMENT_ID, body=body).execute()
document_copy_id = drive_response.get('id')

requests = [
        # One option for replacing all text is to specify all tab IDs.
        {
        'replaceAllText': {
            'containsText': {
                'text': '{{customer-name}}',
                'matchCase':  'true'
            },
            'replaceText': customer_name,
            'tabsCriteria': {
                'tabIds': [TAB_ID_1, TAB_ID_2, TAB_ID_3],
            },
        }},
        # Another option is to omit TabsCriteria if you are replacing across all tabs.
        {
        'replaceAllText': {
            'containsText': {
                'text': '{{date}}',
                'matchCase':  'true'
            },
            'replaceText': str(date),
        }
    }
]

result = service.documents().batchUpdate(
    documentId=document_copy_id, body={'requests': requests}).execute()

Processar listas e tabelas dinâmicas

Uma mesclagem de documentos padrão usa ReplaceAllTextRequest para substituir marcadores de posição individuais únicos (como {{customer-name}} ou {{date}}). No entanto, se os dados incluírem uma lista dinâmica de itens (como linhas em uma fatura, uma lista de produtos encomendados ou uma tabela dinâmica), não será possível usar a substituição de texto padrão, porque o número de itens é desconhecido durante o design do modelo.

Para processar o conteúdo da lista dinâmica, use uma das seguintes estratégias.

Opção 1: anexar linhas a uma tabela de modelo

Se o documento de modelo já contiver uma tabela formatada (por exemplo, com uma linha de cabeçalho e uma única linha de marcador de posição), você poderá clonar e preencher linhas dinamicamente para cada item na lista:

  1. Leia a estrutura do modelo: use o método documents.get para localizar a tabela e identificar o índice da linha do modelo.
  2. Insira novas linhas: para cada item na lista dos seus dados (exceto o primeiro item, que pode reutilizar a linha de modelo existente), chame InsertTableRowRequest para inserir uma nova linha abaixo da linha do modelo.
  3. Preencha os dados da célula:preencha as células na linha do modelo substituindo os marcadores de posição. Para as linhas recém-criadas, use InsertTextRequest para inserir o texto respectivo no local da coordenada de cada célula.

Para exemplos de como inserir linhas de tabela, consulte Trabalhar com tabelas.

Opção 2: substituir uma tag por uma tabela gerada

Se você quiser criar a tabela do zero de forma programática:

  1. Coloque uma tag de marcador de posição: use uma única tag (como {{invoice-table}}) no documento de modelo para marcar onde a lista deve ir.
  2. Localize o marcador de posição: Use uma operação de pesquisa para encontrar o índice inicial da tag.
  3. Exclua o marcador de posição:use DeleteContentRangeRequest para remover o texto {{invoice-table}}.
  4. Insira a tabela: envie um InsertTableRequest nesse índice inicial, especificando o número de linhas e colunas com base na fonte de dados.
  5. Grave valores:preencha cada célula da tabela sequencialmente.

Para exemplos de inserção de tabelas de forma programática, consulte Trabalhar com tabelas.