跳到主要内容

重复段落 - Foreach 循环指南

文档经常包含重复的内容结构,例如项目列表、多个记录或格式相似的重复部分。 PDF4me的模板引擎提供强大的迭代功能,可以从数据集合中动态生成多个段落和章节。


理解 Foreach 循环

foreach 循环是遍历数据集并生成重复内容的主要机制。每次迭代处理数据集中的一个项目并生成相应的输出。

基本 foreach 语法

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

成分:

  • item - 表示迭代中当前元素的变量
  • collection - 要遍历的数据数组或集合
  • 内容块 - 每个项目重复的模板内容

重复段落

通过遍历数据集合并为每个项目创建格式化文本来生成多个段落。

例如:应用评分

模板语法:

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

数据源(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"
}
]
}

生成的输出:

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.

处理空收藏集

当集合可能为空时,请使用 Any() 用于在迭代之前检查数据的方法。这可以防止出现空值异常,并允许您显示其他内容。

基本空值检查

带有 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>>

这种方法:

  1. 检查集合中是否包含任何项
  2. 如果项目可用,则遍历这些项目。
  3. 如果集合为空,则显示备用消息。

嵌套的foreach循环

通过嵌套 foreach 循环来创建层级结构。这对于展示父子关系或多级数据结构非常有用。

例如:部门和员工

模板:

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

数据:

{
"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" }
]
}
]
}

重复复杂部分

foreach 循环可以重复整个内容部分,包括多个段落、格式和嵌套结构。

多段重复

模板:

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

<</foreach>>

此模板会为每个产品生成完整的产品描述块,并保留所有格式和段落分隔符。


条件迭代

将 foreach 循环与条件语句结合使用,可实现选择性内容生成。

示例:条件显示

模板:

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

或者,使用枚举方法:

模板:

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

循环内格式化

在 foreach 循环中对字段应用格式,以实现一致的输出样式。

模板:

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

<</foreach>>

循环变量和索引

使用隐式变量访问循环位置信息(如果您的模板引擎版本支持)。

公共循环变量

  • 当前项目索引(根据实现方式,从 0 开始或从 1 开始)
  • 循环迭代次数
  • 首/末项指示器

用法示例(如果支持):

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

性能考量

循环最佳实践

  1. 限制收集规模 - 在模板处理之前过滤大型集合
  2. 避免深度嵌套 - 为提高性能,请将嵌套循环限制在 2-3 层。
  3. 预处理数据 - 在将数据传递给模板之前执行复杂的计算
  4. 使用高效的查询 - 在数据源级别筛选和排序数据

示例:预筛选数据

而不是:

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

在应用程序中进行预过滤,并传递过滤后的数据:

<<foreach [emp in filteredEmployees]>>

常见模式

模式 1:编号列表

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

模式 2:分组内容

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

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

模式 3:摘要部分

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

故障排除

常见问题

问题: 空引用错误 解决方案: 使用 Any() 在迭代之前检查集合

问题: 多余的换行符或空格 解决方案: 请谨慎管理模板中的空白。

问题: 处理大型数据集时的性能问题 解决方案: 预筛选数据并限制收集大小

问题: 数据绑定错误 解决方案: 请确认属性名称与您的数据结构完全匹配。


实际示例:发票明细项目

完整模板:

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>>

:::提示:复杂迭代

对于复杂的迭代场景,请考虑在将数据传递给模板之前,先在应用程序逻辑中对数据进行预处理。这可以提高模板的可读性和性能。

:::