メインコンテンツへスキップ

段落の繰り返し - Foreachループガイド

文書には、項目のリスト、複数のレコード、類似した書式で繰り返されるセクションなど、繰り返し出現するコンテンツ構造が頻繁に含まれる。 PDF4meのテンプレートエンジンは、データコレクションから複数の段落やセクションを動的に生成するための強力な反復機能を提供します。


foreachループの理解​

の foreach ループは、データコレクションを反復処理し、繰り返しコンテンツを生成するための主要なメカニズムです。各反復処理では、コレクションから1つの項目が処理され、対応する出力が生成されます。

基本的な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() 反復処理の前にデータの有無を確認するメソッド。これにより、null例外を防ぎ、代替コンテンツを表示できるようになります。

基本的なヌルチェック​

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

:::ヒント:複雑な反復処理 複雑な反復処理を行う場合は、データをテンプレートに渡す前に、アプリケーションロジック内で前処理することを検討してください。これにより、テンプレートの可読性とパフォーマンスが向上します。 :::