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 modelo de documento.

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 os dados específicos do usuário ao modelo para criar o documento final.

Essa abordagem é útil por vários motivos:

  • 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 junção de documentos

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

  1. Crie seu documento usando conteúdo de marcador de posição para ajudar no design e na formatação. Toda formatação de texto que você quer substituir é preservada.

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

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

  4. No seu 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 represente o app. As 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 dá aos usuários controle total sobre o documento resultante e evita problemas de escalonamento relacionados aos 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 leiam o documento usando permissions.create na API Drive.
  3. Atualize as permissões para permitir que os criadores de modelos 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 finalizado:

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 fazer essa fusão, use o seguinte código:

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 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 pedidos 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 a criação do modelo.

Para processar conteúdo de 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á tiver 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 sua 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. Inserir novas linhas:para cada item na lista dos seus dados (exceto o primeiro, que pode reutilizar a linha de modelo atual), chame InsertTableRowRequest para inserir uma nova linha abaixo da linha de modelo.
  3. Preencher 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 das coordenadas 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 maneira 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 ficar.
  2. Localize o marcador de posição:use uma operação de pesquisa para encontrar o índice inicial da tag.
  3. Excluir 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 sua fonte de dados.
  5. Escrever valores:preencha cada célula da tabela em sequência.

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