Saltar al contenido principal

Repetir párrafos - Guía del bucle foreach

Los documentos suelen contener estructuras de contenido repetitivas, como listas de elementos, múltiples registros o secciones repetidas con un formato similar. PDF4meEl motor de plantillas proporciona potentes capacidades de iteración para generar dinámicamente múltiples párrafos y secciones a partir de colecciones de datos.


Comprender los bucles foreach

El foreach El bucle es el mecanismo principal para iterar a través de colecciones de datos y generar contenido repetido. Cada iteración procesa un elemento de la colección y genera la salida correspondiente.

Sintaxis básica de Foreach

<<foreach [item in collection]>>
Content with <<[item.property]>>
<</foreach>>

Componentes:

  • item - Variable que representa el elemento actual en la iteración
  • collection - El array o colección de datos que se va a iterar
  • Bloque de contenido: el contenido de la plantilla se repite para cada elemento.

Párrafos repetidos

Genera varios párrafos iterando a través de una recopilación de datos y creando texto formateado para cada elemento.

Ejemplo: Calificaciones de la aplicación

Sintaxis de la plantilla:

<<foreach [app in applications]>><<[app.listAppName]>> in <<[app.listAppType]>> platform is a <<[app.category]>> app and has a <<[app.AppRating]>> rating.
<</foreach>>

Fuente de datos (JSON):

{
"surveyName": "Top-rated Apps",
"applications": [
{
"listAppName": "Instagram",
"listAppType": "iOS",
"category": "Social Media",
"AppRating": "4.9"
},
{
"listAppName": "Whatsapp",
"listAppType": "iOS",
"category": "Chat",
"AppRating": "4.8"
},
{
"listAppName": "Player UG",
"listAppType": "Android",
"category": "Gaming",
"AppRating": "4.75"
}
]
}

Salida generada:

Instagram in iOS platform is a Social Media app and has a 4.9 rating.
Whatsapp in iOS platform is a Chat app and has a 4.8 rating.
Player UG in Android platform is a Gaming app and has a 4.75 rating.

Gestión de colecciones vacías

Cuando una colección pueda estar vacía, utilice la Any() Método para comprobar si hay datos antes de iterar. Esto evita excepciones de valores nulos y permite mostrar contenido alternativo.

Verificación básica de nulidad

Plantilla con comprobación Any():

<<if [applications.Any()]>>
<<foreach [app in applications]>><<[app.listAppName]>> in <<[app.listAppType]>> platform is a <<[app.category]>> app and has a <<[app.AppRating]>> rating.
<</foreach>>
<<else>>No applications listed
<</if>>

Este enfoque:

  1. Comprueba si la colección contiene algún elemento.
  2. Recorre los elementos si están disponibles.
  3. Muestra un mensaje alternativo si la colección está vacía.

Bucles foreach anidados

Crea estructuras jerárquicas anidando bucles foreach. Esto resulta útil para mostrar relaciones padre-hijo o estructuras de datos multinivel.

Ejemplo: Departamento y empleados

Plantilla:

<<foreach [dept in departments]>>
Department: <<[dept.name]>>
<<foreach [emp in dept.employees]>>
- <<[emp.name]>> (<<[emp.position]>>)
<</foreach>>
<</foreach>>

Datos:

{
"departments": [
{
"name": "Engineering",
"employees": [
{ "name": "John Smith", "position": "Senior Developer" },
{ "name": "Jane Doe", "position": "Tech Lead" }
]
},
{
"name": "Marketing",
"employees": [
{ "name": "Mike Johnson", "position": "Marketing Manager" }
]
}
]
}

Secciones complejas repetitivas

Los bucles foreach pueden repetir secciones completas de contenido, incluyendo varios párrafos, formato y estructuras anidadas.

Repetición de varios párrafos

Plantilla:

<<foreach [product in products]>>
Product Name: <<[product.name]>>
Description: <<[product.description]>>
Price: $<<[product.price]>>
Available: <<[product.inStock]>>

<</foreach>>

Esta plantilla genera un bloque de descripción de producto completo para cada producto, manteniendo todo el formato y los saltos de párrafo.


Iteración condicional

Combine bucles foreach con sentencias condicionales para la generación selectiva de contenido.

Ejemplo: Visualización condicional

Plantilla:

<<foreach [employee in employees]>>
<<if [employee.age > 50]>>
Senior Employee: <<[employee.name]>> - Age: <<[employee.age]>>
<</if>>
<</foreach>>

Como alternativa, utilice métodos de enumeración:

Plantilla:

<<foreach [employee in employees.Where(e => e.age > 50)]>>
Senior Employee: <<[employee.name]>> - Age: <<[employee.age]>>
<</foreach>>

Formato dentro de bucles

Aplique formato a los campos dentro de los bucles foreach para obtener un estilo de salida uniforme.

Plantilla:

<<foreach [customer in customers]>>
Customer: <<[customer.name]:caps>>
Last Visit: <<[customer.lastVisit]:"MMMM dd, yyyy">>
Status: <<[customer.status]:upper>>

<</foreach>>

Variables de bucle e indexación

Acceda a la información de la posición del bucle utilizando variables implícitas (si su versión del motor de plantillas lo admite).

Variables comunes de bucle

  • Índice del artículo actual (basado en 0 o en 1, según la implementación)
  • Número de iteraciones del bucle
  • Indicadores de primer/último artículo

Ejemplo de uso (si es compatible):

<<foreach [item in items]>>
<<[$index + 1]>>. <<[item.name]>>
<</foreach>>

Consideraciones de rendimiento

Mejores prácticas para bucles

  1. Limitar el tamaño de la colección - Filtrar colecciones grandes antes del procesamiento de plantillas
  2. Evite la anidación profunda - Limita los bucles anidados a 2-3 niveles para un mejor rendimiento.
  3. Preprocesar datos - Realizar cálculos complejos antes de pasar los datos a las plantillas.
  4. Utilice consultas eficientes - Filtrar y ordenar los datos a nivel de la fuente de datos.

Ejemplo: Datos prefiltrados

En lugar de:

<<foreach [emp in employees.Where(e => e.age > 30).OrderBy(e => e.name)]>>

Prefiltra en tu aplicación y pasa los datos filtrados:

<<foreach [emp in filteredEmployees]>>

Patrones comunes

Patrón 1: Lista numerada

<<foreach [item in items]>>
<<[$index]>>. <<[item.title]>>
<</foreach>>

Patrón 2: Contenido agrupado

<<foreach [category in categories]>>
## <<[category.name]>>

<<foreach [item in category.items]>>
- <<[item.name]>>
<</foreach>>
<</foreach>>

Patrón 3: Sección de resumen

<<foreach [report in reports]>>
Report: <<[report.title]>>
Total Records: <<[report.records.Count()]>>
Average Value: <<[report.records.Average(r => r.value)]>>
<</foreach>>

Solución de problemas

Problemas comunes

Asunto: Errores de referencia nula Solución: Usar Any() para comprobar las colecciones antes de la iteración

Asunto: Saltos de línea o espacios no deseados Solución: Gestiona cuidadosamente los espacios en blanco en tu plantilla.

Asunto: Problemas de rendimiento con colecciones grandes Solución: Prefiltrar datos y limitar el tamaño de las colecciones.

Asunto: Enlace de datos incorrecto Solución: Verifique que los nombres de las propiedades coincidan exactamente con su estructura de datos.


Ejemplo práctico: Partidas de una factura

Plantilla completa:

Invoice #<<[invoiceNumber]>>
Date: <<[invoiceDate]:"dd.MM.yyyy">>

Items:
<<if [lineItems.Any()]>>
<<foreach [item in lineItems]>>
<<[item.name]:caps>> - Qty: <<[item.quantity]>> - Price: $<<[item.price]:"F2">> - Total: $<<[item.quantity * item.price]:"F2">>
<</foreach>>

Subtotal: $<<[lineItems.Sum(i => i.quantity * i.price)]:"F2">>
<<else>>
No items in this invoice.
<</if>>

:::Consejo Iteraciones complejas Para escenarios de iteración complejos, considere preprocesar los datos en la lógica de su aplicación antes de pasarlos a la plantilla. Esto mejora la legibilidad y el rendimiento de la plantilla.

:::