Combinar texto en un documento

En esta guía, se explica cómo usar la API de Google Docs para combinar información de una o más fuentes de datos externas en un documento de plantilla existente.

Una plantilla es un tipo de documento que contiene texto fijo y marcadores de posición para contenido dinámico. Por ejemplo, una plantilla de contrato puede contener texto fijo con marcadores de posición para el nombre y la dirección del destinatario. Luego, la app combina los datos específicos del usuario en la plantilla para crear el documento terminado.

Existen varios motivos por los que este enfoque es útil:

  • Los diseñadores pueden ajustar el diseño de un documento con Documentos de Google. Esto es más sencillo que ajustar los parámetros en tu app para establecer el diseño renderizado.

  • Separar el contenido de la presentación es un principio de diseño conocido con muchos beneficios.

Diagrama que muestra cómo los datos de una fuente se combinan en una plantilla para crear un documento.
Figura 1. Combinación de datos en una plantilla para crear un documento

Cómo funciona la combinación de documentos

Este es un ejemplo de cómo puedes usar la API de Docs para combinar datos en un documento:

  1. Crea tu documento con contenido de marcador de posición para ayudarte con el diseño y el formato. Se conserva cualquier formato de texto que desees reemplazar.

  2. Para cada elemento que insertarás, reemplaza el contenido del marcador de posición por una etiqueta. Asegúrate de usar cadenas que no es probable que ocurran normalmente. Por ejemplo, {{account-holder-name}} podría ser una buena etiqueta.

  3. En tu código, usa la API de Google Drive para hacer una copia del documento.

  4. En tu código, usa el método batchUpdate de la API de Docs con el nombre del documento e incluye un ReplaceAllTextRequest.

Los IDs de los documentos hacen referencia a un documento y se pueden derivar de la URL:

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

Administrar plantillas

Para los documentos de plantilla que la app define y posee, crea la plantilla con una cuenta dedicada que represente la app. Las cuentas de servicio son una buena opción y evitan complicaciones con las políticas de Google Workspace que restringen el uso compartido.

Cuando crees instancias de documentos a partir de plantillas, siempre usa credenciales de usuario final. Esto les brinda a los usuarios control total sobre el documento resultante y evita problemas de escalamiento relacionados con los límites por usuario en Google Drive.

Para crear una plantilla con una cuenta de servicio, sigue estos pasos con las credenciales de la app:

  1. Crea un documento con documents.create en la API de Docs.
  2. Actualiza los permisos para permitir que los destinatarios del documento lo lean con permissions.create en la API de Drive.
  3. Actualiza los permisos para permitir que los autores de la plantilla escriban en ella con permissions.create en la API de Drive.
  4. Edita la plantilla según sea necesario.

Para crear una instancia del documento, sigue estos pasos con las credenciales del usuario:

  1. Crea una copia de la plantilla con files.copy en la API de Drive.
  2. Reemplaza los valores con documents.batchUpdate en la API de Docs.

Ejemplo: Combina datos en una plantilla

En el siguiente ejemplo de código, se muestra cómo reemplazar dos campos en todas las pestañas de una plantilla con valores reales para generar un documento terminado:

Imagen que muestra una plantilla de documento con marcadores de posición de etiquetas y el documento combinado resultante.
Figura 2. Reemplazo de marcadores de posición de etiquetas por valores

Para realizar esta combinación, usa el siguiente 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()

Cómo controlar listas y tablas dinámicas

Una combinación de documentos estándar usa ReplaceAllTextRequest para reemplazar marcadores de posición individuales únicos (como {{customer-name}} o {{date}}). Sin embargo, si tus datos incluyen una lista dinámica de elementos (como líneas en una factura, una lista de productos pedidos o una tabla dinámica), no puedes usar el reemplazo de texto estándar porque la cantidad de elementos es desconocida durante el diseño de la plantilla.

Para controlar el contenido de la lista dinámica, usa una de las siguientes estrategias.

Opción 1: Agrega filas a una tabla de plantilla

Si tu documento de plantilla ya contiene una tabla con formato (por ejemplo, con una fila de encabezado y una sola fila de marcador de posición), puedes clonar y completar filas de forma dinámica para cada elemento de tu lista:

  1. Lee la estructura de la plantilla: Usa el método documents.get para ubicar la tabla y, luego, identificar el índice de la fila de la plantilla.
  2. Inserta filas nuevas: Para cada elemento de tu lista de datos (excepto el primer elemento, que puede reutilizar la fila de plantilla existente), llama a InsertTableRowRequest para insertar una fila nueva debajo de la fila de la plantilla.
  3. Completa los datos de la celda: Completa las celdas de la fila de la plantilla reemplazando sus marcadores de posición. Para las filas recién creadas, usa InsertTextRequest para insertar el texto respectivo en la ubicación de coordenadas de cada celda.

Para ver ejemplos de cómo insertar filas de tabla, consulta Trabaja con tablas.

Opción 2: Reemplaza una etiqueta por una tabla generada

Si deseas compilar la tabla desde cero de forma programática, haz lo siguiente:

  1. Coloca una etiqueta de marcador de posición: Usa una sola etiqueta (como {{invoice-table}}) en el documento de plantilla para marcar dónde debe ir la lista.
  2. Ubica el marcador de posición: Usa una operación de búsqueda para encontrar el índice de inicio de la etiqueta.
  3. Borra el marcador de posición: Usa DeleteContentRangeRequest para quitar el texto {{invoice-table}}.
  4. Inserta la tabla: Envía un InsertTableRequest en ese índice de inicio y especifica la cantidad de filas y columnas según tu fuente de datos.
  5. Escribe valores: Completa cada celda de la tabla de forma secuencial.

Para ver ejemplos de cómo insertar tablas de forma programática, consulta Trabaja con tablas.