パーソナライゼーション構文 personalization-syntax

このページ:​一般的なルール、予約済みのキーワード、タイプ強制、使用可能な名前空間、ベストプラクティスなど、Adobe Journey Optimizer での Handlebars と PQL のパーソナライゼーション構文について説明します。

Journey Optimizer のパーソナライゼーションでは、同じの式で一緒に機能する次の 2 つの補完的な構文が使用されます。

  • Handlebars({{...}})- プロファイル属性のレンダリング、配列のループ、ブロックヘルパーの呼び出しに使用されます。 詳しくは、HandlebarsJS ドキュメントを参照してください。
  • Profile Query Language(PQL)({%= ... %})- ビルトイン関数(例:upperCase()、formatDate()、dateDiff())の呼び出しや、条件式の評価に使用されます。

ランタイムエラーを回避するには、どのコンテキストにいるかを理解することが重要です。 例えば、{{...}} 内に PQL 関数呼び出しを配置すると失敗します。これは、Handlebars が PQL 式として評価するのではなく、ヘルパーとして解決しようとするからです。

例:

ユースケース
構文
プロファイル属性のレンダリング
{{profile.person.name.firstName}}
PQL 関数の呼び出し
{%= upperCase(profile.person.name.firstName) %}
条件付きブロック
{%#if profile.loyalty.tier = "gold"%}...{%/if%}
配列のループ
{{#each profile.orders}}...{{/each}}

属性の構造は、Adobe Experience Platform XDM スキーマで定義されます。 学習を増やす。

TIP
日付の書式設定、カウントダウン、条件付きフォールバックなど、これらの構文を実際のシナリオに適用したすぐに使用できる式について詳しくは、パーソナライゼーションのレシピ​ページを参照してください。

構文の一般的なルール general-rules

  • 識別子には、Handlebars 構文用に予約されている次の特殊文字を除く任意の Unicode 文字を使用できます。

    code language-none
    Whitespace ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~
    
  • 構文では大文字と小文字が区別されます。

  • true、false、null および undefined​という語は、パス式の最初の部分でのみ使用できます。

  • Handlebars では、{{expression}} から返される値は HTML エスケープ​されています。 式に「&」が含まれている場合、返される HTML エスケープ出力は「&amp;」として生成されます。 Handlebars の値をエスケープしない場合は、「トリプルスタッシュ」を使用します。

    フィールド profile.person.name の値が「Mark & Mary」であるとします。 構文 {{profile.person.name}} には Mark &amp; Mary が表示され、{{{profile.person.name}}} には Mark & Mary が表示されます。

  • リテラル関数の引数に関して、テンプレート言語パーサーはエスケープされない単一のバックスラッシュ(\)記号をサポートしていません。 この文字は、バックスラッシュ(\)記号を追加してエスケープする必要があります。 例:

    {%= regexGroup("abc@xyz.com","@(\\w+)", 1)%}

  • 文字列値内に​ リテラルな二重引用符 ​を含めるには(例:JSON 出力の生成時)、バックスラッシュ(\")でエスケープします。

    code language-handlebars
    { "message": "Hello \"{{profile.person.name.firstName}}\"" }
    

    出力:{ "message": "Hello \"John\"" }

    または、値自体に HTML エンコードしない特殊文字が含まれている場合は、トリプルスタッシュ {{{ }}} を使用して、エスケープされていない HTML を出力します。

予約済みのキーワード reserved-keywords

特定のキーワードは、Profile Query Language(PQL)で予約され、パーソナライゼーション式のフィールド名または変数名として直接使用できません。 XDM スキーマに予約済みのキーワードと一致する名前のフィールドが含まれている場合、式で参照するには、バックティック(`)を使用してエスケープする必要があります。

予約済みのキーワードは次のとおりです。

  • 一般:let, export, to, as, this, last, next, now, NOW, today, yesterday, tomorrow, from, FROM, From, before, BEFORE, Before, after, AFTER, After
  • 時間単位:millisecond, milliseconds, second, seconds, minute, minutes, hour, hours, day, days, week, weeks, month, months, year, years, decade, decades, century, centuries, millennium, millennia
  • ブール演算子および論理演算子:true、TRUE、True、false、FALSE、False、not、NOT、Not、and、AND、And、or、OR、Or、null、NULL、Null

例:

プロファイルスキーマに next という名前のフィールドがある場合は、バックティックで囲む必要があります。

{{profile.person.`next`.name}}

バックティックがないと、パーソナライゼーションエディターは検証に失敗し、エラーが発生します。

NOTE
予約済みキーワードに対するバックティックエスケープは、{{...}} の Handlebars パスと {%= ... %} の PQL 式の両方に適用されます。これは、これらのキーワードがパス解決レベルで予約されているからです。 これは、バックティックエスケープが PQL 式内でのみサポートされているハイフネーション処理されたフィールド名とは異なります。 ハイフネーション処理された属性キーを参照してください。

特殊属性キーの PQL 構文ルール pql-special-keys

予約済みのキーワード以外にも、PQL 式でバックティックエスケープが必要になるケースが 2 つあります。

ハイフネーション処理された属性キー hyphenated-keys

XDM スキーマに、ハイフン付きのフィールド名(例:my-field、event-type)や、数字で始まるまたは数字を含むフィールド名がが含まれている場合は、PQL 式内でキーをバックティックで囲みます。

{%= profile.events.`order-total` > 100 %}
NOTE
バックティックエスケープは、PQL式({%= ... %})内でのみサポートされています。 Handlebars の補間({{...}})ではサポートされていません。 ハイフネーション処理されたフィールド名は {{...}} ブロック(例:{{profile.my-custom-field}})で直接参照できます。バックティック構文のみがそこでエラーになります。

PQL 式でバックティックを使用しない場合、ハイフンは減算演算子として解釈され、PQL 構文エラーが発生します。

コンテキスト属性の数値イベント ID numeric-event-ids

イベント ID が数値(例:1697323153)であるコンテキストイベント属性を参照する場合は、バックティックで囲みます。 これは、formatDate() などの関数内でも適用されます。

{% let ts = formatDate(toDateTime(context.journey.events.`1697323153`.timestamp), "dd/MM/yyyy") %}
{{ts}}

タイプ強制 type-coercion

PQL は強くタイプ付けされています。 値を比較または渡す場合、両方の側を同じタイプにする必要があります。 よくあるケース:

シナリオ
ソリューション
文字列として格納された数値
算術または比較の前に stringToNumber() を使用します。{%= stringToNumber(profile.loyalty.pointsBalance) > 500 %}
文字列として格納された整数
算術の前に string_to_integer() または stringToNumber() を使用します
文字列として格納されたブール値
変換するには、toBool() を使用します。{%= toBool(profile.consents.email.val) = true %}

使用可能な名前空間 namespaces

  • プロファイル

    この名前空間を使用すると、プロファイルスキーマで定義されているすべての属性を参照できます。このスキーマについて詳しくは、Adobe Experience Platform データモデル(XDM)のドキュメントを参照してください。

    属性は、Journey Optimizer のパーソナライゼーションブロックで参照する前に、スキーマで定義しておく必要があります。

    条件でプロファイル属性を活用する方法について詳しくは、この節を参照してください。

    accordion
    サンプルリファレンス
    • {{profile.person.name.fullName}}
    • {{profile.person.name.firstName}}
    • {{profile.person.gender}}
    • {{profile.personalEmail.address}}
    • {{profile.mobilePhone.number}}
    • {{profile.homeAddress.city}}
    • {{profile.faxPhone.number}}
  • オーディエンス

    セグメント化サービスについて詳しくは、このドキュメントを参照してください。

  • オファー

    この名前空間では、既存のオファー決定を参照できます。

    オファーを参照するには、オファーを定義する様々な情報を使用してパスを宣言する必要があります。 このパスの構造は次のようになります。

    offers.Type.[Placement Id].[Activity Id].Attribute

    ここで:

    • offers はオファー名前空間に属するパス式を識別します。
    • Type はオファー表示域のタイプを決定します。 image、html および text などの値が使用されます。
    • Placement Id と Activity Id は配置とアクティビティの識別子です。
    • Attributes は、オファータイプに依存するオファー固有の属性です。 例:deliveryUrl(画像の場合)

    決定 API とオファー表示域について詳しくは、このページを参照してください。

    すべての参照は、このページで説明されている検証メカニズムを使用して、オファースキーマに対して検証されます

    accordion
    サンプルリファレンス
    • 画像がホストされる場所:

      offers.image.[offers:xcore:offer-placement:126f767d74b0da80].[xcore:offer-activity:125e2c6889798fd9].deliveryUrl

    • 画像をクリックしたときのターゲット URL:

      offers.image.[offers:xcore:offer-placement:126f767d74b0da80].[xcore:offer-activity:125e2c6889798fd9].linkUrl

    • 決定エンジンから得られるオファーのテキストコンテンツ:

      offers.text.[offers:xcore:offer-placement:126f767d74b0da80].[xcore:offer-activity:125e2c6889798fd9].content

    • 決定エンジンから得られるオファーの HTML コンテンツ:

      offers.html.[offers:xcore:offer-placement:126f767d74b0da80].[xcore:offer-activity:125e2c6889798fd9].content

ヘルパー helpers-all

Handlebars ヘルパーは、パラメーターの後に付けられる単純な識別子です。 各パラメーターは、Handlebars 式です。 これらのヘルパーは、テンプレート内の任意のコンテキストからアクセスできます。

これらのブロックヘルパーは、ヘルパー名の先頭にある # で識別され、対となる同じ名前の / タグで閉じる必要があります。

ブロックは、ブロック開始タグ({{# }})と終了タグ({{/}})を持つ式です。

ヘルパー関数について詳しくは、この節を参照してください。

リテラル型 literal-types

Adobe Journey Optimizer では、次のリテラル型をサポートしています。

リテラル
定義
文字列
1 つ以上の文字で構成され、二重引用符で囲まれたデータタイプです。
例:"prospect"、"jobs"、"articles"
ブール
true か false のいずれかであるデータタイプです。
整数
整数を表すデータタイプです。 正、負、ゼロのいずれかです。
例:-201、0、412
配列
他のリテラル値のグループとして構成されるデータ型です。 複数の値を区切る場合は、角括弧で囲んでグループ化し、カンマで区切ります。
メモ:配列内の項目のプロパティに直接アクセスすることはできません。
例:[1, 4, 7]、["US", "FR"]
CAUTION
xEvent 変数は、パーソナライズ式では使用できません。 xEvent を参照すると、検証エラーが発生します。

ベストプラクティス best-practices

パーソナライゼーション式を作成する前に、これらの構文ルールを確認します。 ほとんどのランタイムエラーは、Handlebars と PQL のコンテキストを混在させることから発生します。

正しい条件付きブロック構文を使用する

常に {%#if%}/{%else if%}/{%else%}/{%/if%} を使用します。 {% if %}/{% elseif %}/{% endif %} 構文はサポートされていません。

{%#if profile.loyalty.tier = "gold"%}
Gold member content
{%else if profile.loyalty.tier = "silver"%}
Silver member content
{%else%}
Default content
{%/if%}

{{...}} Handlebars ブロック内で PQL 関数を呼び出さない

{{...}} は Handlebars 変数とヘルパーのみを解決します。PQL は評価されません。 upperCase() などの PQL 関数を {{...}} で囲むと、「ヘルパーが見つかりませんでした」エラーが発生します。 代わりに、{%= ... %} 呼び出しを使用します。

不正確
正確
{{upperCase(cleanName)}}
{%= upperCase(cleanName) %}

{{#each}} と{%#if%} を組み合わせる際は、名前付きのループエイリアスを使用する

this.field は Handlebars レンダラーによって解決されますが、{%#if%} 条件内の PQL 評価基準では解決されません。 as |item| を使用して名前付きエイリアスを定義し、両方のコンテキストでフィールドを解決できるようにします。

{{#each profile.orders as |order|}}
  {%#if order.status = "pending"%}
  Order {{order.id}} is pending.
  {%/if%}
{{/each}}

ループの前に、PQL 関数の結果を変数に割り当てる

topN などの PQL UDF は、{{#each}} 内から直接呼び出すことはできません。 最初に {% let %} でこれらを評価し、その結果を反復処理します。

{% let topOrders = topN(profile.orders, price, 3) %}
{{#each topOrders}}
  {{this.name}} — {{this.price}}&euro;
{{/each}}

関数呼び出しの繰り返しを避けるために {% let %} を使用する

計算された値が複数回必要な場合は、変数に格納します。 これにより、読みやすさが向上し、冗長な評価を防ぐことができます。

{% let cleanName = replaceAll(profile.person.name.firstName, "[^a-zA-Z]", "") %}
Hi {{cleanName}}, your code is: WELCOME-{%= upperCase(cleanName) %}

dateDiff に正しい引数の順序を使用する

dateDiff(start, end) は、先に早い日付を指定します。 今後の日付までの残り日数を計算するには、現在の日付を最初の引数として渡します。

{% let daysLeft = dateDiff(getCurrentZonedDateTime(), stringToDate(profile.loyalty.expiryDate)) %}

PQL での等価比較には、== ではなく、= を使用する

PQL では、等価性の判定に単一の = 演算子を使用します。 == を使用すると、構文エラーが発生します。

ハイフネーション処理されたフィールド名にはバックティックを使用する - PQL 式でのみ

XDM スキーマフィールド名にハイフン(例:order-total)が含まれる場合は、ハイフンが減算演算子として解析されないように、フィールド名をバックティックで囲みます。 これは、{%= ... %} PQL 式内でのみサポートされ、{{...}} Handlebars ブロック内ではサポートされていません。

{%= profile.events.`order-total` > 100 %}

コンテンツに直接コピーできる、すぐに使用できる式について詳しくは、パーソナライゼーションのレシピ ​を参照してください。

AI Knowledge Reference

This section contains structured knowledge intended to support interpretation, retrieval, and question answering related to this topic.

For complete understanding, this information should be combined with the documentation on this page. Neither source is intended to stand alone; the page describes the feature, while this section provides additional context that helps disambiguate terminology, intent, applicability, and constraints.

  • TL;DR: This page explains the Handlebars and PQL personalization syntaxes in Journey Optimizer — their general rules, reserved keywords, namespace structure, type system, and best practices for avoiding common runtime errors.

Intents:

  • Understand when to use Handlebars ({{...}}) vs. PQL ({%= ... %}) syntax
  • Apply general syntax rules: reserved characters, case sensitivity, HTML escaping, backslash handling
  • Escape reserved keywords and special attribute keys (hyphenated names, numeric event IDs) correctly
  • Apply type coercion when comparing or passing values of mismatched types
  • Reference personalization from the available namespaces: Profile, Audience, Offers
  • Follow best practices to avoid the most common runtime and validation errors

Glossary:

  • Handlebars: The {{...}} templating syntax used for rendering attributes, looping over arrays, and calling block helpers; HTML-escapes output by default. (product-specific)
  • Profile Query Language (PQL): The {%= ... %} expression syntax used for calling built-in functions (e.g. upperCase(), formatDate()) and evaluating conditional expressions. (product-specific)
  • Triple-stash ({{{ }}}): A Handlebars syntax variant that outputs values without HTML escaping, useful when the value itself contains HTML characters that should not be encoded.
  • Reserved keywords: PQL identifiers that cannot be used directly as field or variable names, grouped as general keywords (let, export, to, as, this, last, next, now, NOW, today, yesterday, tomorrow, from, FROM, From, before, BEFORE, Before, after, AFTER, After), time units (millisecond, milliseconds, second, seconds, minute, minutes, hour, hours, day, days, week, weeks, month, months, year, years, decade, decades, century, centuries, millennium, millennia), and boolean/logical operators (true, TRUE, True, false, FALSE, False, not, NOT, Not, and, AND, And, or, OR, Or, null, NULL, Null); must be wrapped in backticks when a schema field uses one of these names.
  • Type coercion: The explicit conversion of a value from one data type to another (e.g. string → number) using functions like stringToNumber() or toBool(), required before comparison or arithmetic in PQL.
  • Namespace: The top-level grouping of personalization data — Profile, Audience, Offers — each with its own path structure and access rules.
  • Block helper: A Handlebars helper identified by # before the helper name and a matching closing /, used for block constructs like {{#each}}.

Guardrails:

  • The xEvent variable is not available in personalization expressions; any reference to xEvent results in validation failures.
  • PQL function calls inside {{...}} Handlebars blocks will fail; use {%= ... %} instead.
  • The {% if %} / {% elseif %} / {% endif %} conditional syntax is not supported; use {%#if%} / {%else if%} / {%/if%}.
  • Backtick escaping for hyphenated field names is only supported inside PQL expressions ({%= ... %}). In {{...}} Handlebars interpolation, backtick syntax fails — but hyphenated field names can still be referenced directly (e.g. {{profile.my-custom-field}}).
  • Reserved keywords (general, time-unit, and boolean/logical, e.g. next, last, this, day, year, true, and, or) must be wrapped in backticks when used as schema field names; applies to both {{...}} and {%= ... %}.
  • Single backslash \ is not supported as a literal function argument; use double backslash \\.
  • PQL is strongly typed; mismatched types in comparisons or arithmetic require explicit conversion using stringToNumber(), toBool(), or similar coercion functions.

Terminology:

  • Canonical name: Handlebars — for the {{...}} syntax; PQL — for the {%= ... %} syntax
  • Do not confuse: {{...}} (Handlebars — renders variables and helpers, HTML-escaped) ≠ {%= ... %} (PQL — evaluates functions and expressions) ≠ {%#if%} / {%/if%} (conditional block syntax, percent-curly braces)
  • Do not confuse: {{profile.person.name}} (single-stash — HTML-escaped output) ≠ {{{profile.person.name}}} (triple-stash — unescaped output)
  • Do not confuse: reserved keyword backtick escaping (applies to both {{...}} and {%= ... %}) ≠ hyphenated key backtick escaping (only supported inside {%= ... %} PQL expressions, not in {{...}})
  • Do not confuse: = (PQL equality operator — correct) ≠ == (not valid PQL — causes a syntax error)

FAQ:

  • Q: When should I use {{...}} vs. {%= ... %}? — Use {{...}} (Handlebars) to render attribute values, loop over arrays, and call block helpers. Use {%= ... %} (PQL) to call built-in functions like upperCase() and formatDate(), and to evaluate conditional expressions.
  • Q: How do I output a value without HTML encoding? — Use the triple-stash {{{ }}} instead of {{...}}. Single-brace Handlebars HTML-escapes output (e.g., & becomes &amp;); triple-stash bypasses escaping.
  • Q: What is the correct equality operator in PQL? — Use a single = for equality comparisons in PQL. Using == is a syntax error.
  • Q: How do I reference a schema field whose name is a reserved keyword (e.g. next, last, this)? — Wrap it in backticks: {{profile.person.\next`.name}}`. This applies to both Handlebars paths and PQL expressions.
  • Q: Can I call PQL functions inside {{...}} Handlebars blocks? — No. {{...}} resolves Handlebars variables and helpers only. A PQL function inside {{...}} causes a “could not find helper” error. Use {%= functionName(...) %} instead.
recommendation-more-help
journey-optimizer-help