Skip to content

Expression Tokens v5.0

Expression tokens let you format, calculate, and conditionally display data right inside your views, forms, and feeds — no SQL changes or JavaScript needed. Use them to display prices as currency, format dates, calculate totals with tax, show "In Stock" or "Out of Stock" based on your data, apply CSS classes conditionally, combine fields inside tag properties, provide fallback values for missing data, and more.

Introduction

Standard field tokens like [[ProductName]] insert raw values. Expression tokens wrap those values in logic:

[[=Upper(ProductName)]]
[[=Round(Price * 1.0825, 2)]]
[[=If(QtyInStock > 0, 'In Stock', 'Out of Stock')]]

Notice that inside an expression, you use the field name by itself — ProductName instead of [[ProductName]]. The expression already lives inside [[=...]], so the extra brackets aren't needed.

Previously, this kind of formatting and logic required changes to your SQL queries, custom JavaScript, or other workarounds. Expression tokens let you do it all directly in your view, form, or feed markup.

When to Use Expression Tokens

Much of what you do in XMP views, forms, and feeds involves placing field tokens directly in your HTML markup. That approach is simple and works great — you don't need expression tokens for everything. This section helps you understand when plain tokens are enough and when expression tokens are the better tool.

Plain HTML: Just Use Tokens

Inside your <ItemTemplate>, <DetailTemplate>, or anywhere you're writing regular HTML, you can place field tokens side by side and they simply output their values into the markup:

html
<!-- Combining fields — just place them next to each other -->
<span>[[FirstName]] [[LastName]]</span>

<!-- Building URLs and paths -->
<img src="/Portals/0/Images/[[PhotoFile]]" />
<a href="/products?id=[[ProductID]]">[[ProductName]]</a>

<!-- Mixing tokens with HTML structure -->
<div class="card">
  <h3>[[Title]]</h3>
  <p>[[Description]]</p>
  <span>[[City]], [[State]] [[Zip]]</span>
</div>

This works because the HTML is plain text as far as XMP is concerned — it replaces each [[...]] token with its value and sends the result to the browser. No expression token needed.

Tag Properties: Where Plain Tokens Fall Short

The situation changes when you need to place a combined value inside a property of an XMP tag or ASP.NET server control. These properties expect a single evaluated value, so you can't just drop multiple tokens side by side:

html
<!-- ✗ This WON'T work — you can't put two tokens in a single tag property -->
<xmod:DetailButton Text="View [[FirstName]] [[LastName]]" />

<!-- ✓ Use the & operator to concatenate -->
<xmod:DetailButton Text="[[='View ' & FirstName & ' ' & LastName]]" />

<!-- ✓ Or use the Concat function -->
<xmod:DetailButton Text="[[=Concat('View ', FirstName, ' ', LastName)]]" />

Both approaches produce a single [[=...]] value that the tag property can evaluate. The & operator is concise and natural for simple cases; Concat is handy when you have many values to join. This is one of the most common reasons to reach for expression tokens.

Formatting and Logic: Where Expression Tokens Shine

Even in plain HTML, expression tokens become the right choice when you need to do more than just insert a raw value:

Formatting

html
<!-- Plain token gives you the raw value: 19.99 -->
<span>[[Price]]</span>

<!-- Expression token lets you format it: $19.99 -->
<span>[[=Format(Price, 'C2')]]</span>

<!-- Format a date: Jan 15, 2026 instead of 1/15/2026 12:00:00 AM -->
<span>[[=Format(EventDate, 'MMM d, yyyy')]]</span>

Calculations

html
<!-- Tax-inclusive price -->
<span>[[=Format(Round(Price * 1.0825, 2), 'C2')]]</span>

<!-- Discount percentage -->
<span>[[=Round((1 - SalePrice / RegularPrice) * 100, 0)]]% off</span>

Conditional output

html
<!-- Show different text based on data -->
<span>[[=If(QtyInStock > 0, 'In Stock', 'Out of Stock')]]</span>

<!-- Apply a CSS class based on data -->
<tr class="[[=If(IsActive, 'active', 'inactive')]]">

Handling missing data

html
<!-- Fall back to a default when a field is empty -->
<span>[[=Coalesce(Nickname, FirstName, 'Anonymous')]]</span>

Previously, these kinds of operations required changes to your SQL queries, custom JavaScript, or other workarounds. Expression tokens let you handle them right in your markup.

The <xmod:Format> Control

XMP also has the <xmod:Format> control, which has been available since early versions. For simple date and number formatting, either tool works well — use whichever feels more natural. But <xmod:Format> has capabilities that expression tokens don't:

Culture-aware formatting — format values for a specific locale, regardless of the server's default culture:

html
<!-- Force British currency formatting, even on a US server -->
<xmod:Format Type="Float" Value='[[Price]]' Pattern="c" OutputCulture="en-GB" />
<!-- Output: £5.00 -->

<!-- Parse a US date and display it for a French audience -->
<xmod:Format Type="Date" Value='[[EventDate]]' InputCulture="en-US" OutputCulture="fr-FR" />
<!-- Output: 25/04/2013 -->

Expression tokens use the server's default culture for formatting. If you need to target a specific locale, <xmod:Format> is the right tool.

Regex substitutions — transform text using regular expression patterns:

html
<xmod:Format Type="RegEx" Value='[[PhoneNumber]]'
    Pattern="(\d{3})(\d{3})(\d{4})"
    Replacement="($1) $2-$3" />
<!-- Input: 5035551234 → Output: (503) 555-1234 -->

Email cloaking — obfuscate email addresses so web scrapers can't harvest them:

html
<xmod:Format Type="Cloak" Value='[[Email]]' />

Truncation with ellipsis — trim long text to a maximum length:

html
<xmod:Format Type="Text" Value='[[Description]]' MaxLength="100" />

When to choose which?

For most formatting tasks — dates, currency, numbers — expression tokens and <xmod:Format> overlap. Expression tokens are more concise ([[=Format(Price, 'C2')]] vs. an entire <xmod:Format> tag) and can be placed anywhere, including inside HTML attributes. Choose <xmod:Format> when you need culture control, regex, or cloaking.

Quick Reference

ScenarioApproach
Displaying a field value in HTMLPlain token: [[FieldName]]
Combining fields in HTMLPlain tokens side by side: [[First]] [[Last]]
Combining fields in a tag propertyExpression: [[=First & ' ' & Last]]
Formatting dates or numbersExpression: [[=Format(Price, 'C2')]]
Math and calculationsExpression: [[=Round(Price * 1.08, 2)]]
Conditional text or CSS classesExpression: [[=If(Qty > 0, 'In Stock', 'Out')]]
Fallback for missing valuesExpression: [[=Coalesce(Phone, 'N/A')]]
Culture-specific formatting<xmod:Format> with OutputCulture
Regex text substitutions<xmod:Format> with Type="RegEx"
Email cloaking<xmod:Format> with Type="Cloak"

Syntax

Expression tokens use the [[=...]] format. The = prefix distinguishes them from standard field tokens. An easy way to remember the syntax is to think of it like entering a formula into your spreadsheet. You normally type = and your function. Here, you simply add that = to your token to use a function:

[[=expression]]

The expression inside can contain field names, literals, operators, and function calls. Whitespace is ignored.

Quick Examples

html
<!-- Price with tax -->
<span>[[=Format(Round(Price * 1.0825, 2), 'C2')]]</span>

<!-- Uppercase product name -->
<h3>[[=Upper(ProductName)]]</h3>

<!-- Stock status badge -->
<span class="badge [[=If(QtyInStock > 0, 'badge-success', 'badge-danger')]]">
  [[=If(QtyInStock > 10, 'In Stock', If(QtyInStock > 0, 'Low Stock', 'Out of Stock'))]]
</span>

<!-- User initials avatar -->
<div class="avatar">[[=Concat(Upper(Left(FirstName, 1)), Upper(Left(LastName, 1)))]]</div>

<!-- Discount percentage -->
<span>[[=Round((1 - SalePrice / RegularPrice) * 100, 0)]]% off</span>

<!-- Fallback chain for display name -->
<span>[[=Coalesce(Nickname, FirstName, Email)]]</span>

<!-- Personalized greeting using system token -->
<p>[[=Concat('Welcome, ', ${User:DisplayName}, '!')]]</p>

Field References

Inside an expression, field names are written without the double-bracket syntax. The expression evaluator looks up field values from the current data row automatically.

SyntaxDescriptionExample
FieldNameBare field name[[=Upper(ProductName)]]
$FieldNameDollar-prefixed, when the name matches a function[[=$Round + 1]]
${Field Name}Braced, for names with spaces[[=${First Name}]]

When to Use $ Prefix

In rare circumstances, your field name may match the name of a built-in function like a column called Round or Max. In those cases, XMod Pro would interpret it as a function call.

To work around this, you can change your field name in SQL using the AS clause. If that's not possible or desirable, use the $ prefix to tell XMod Pro you mean the field, not the function:

[[=Round($Round, 2)]]

Here, Round(...) is the function call and $Round is the field named "Round".

Fields with Spaces

Wrap field names that contain spaces in ${...}:

[[=Upper(${First Name})]]

Missing Fields

If a field doesn't exist in the current data row, it returns an empty string — the same behavior as standard [[NonExistentField]] tokens.

System Tokens in Expressions

You can use DNN system tokens inside expressions using the ${Type:Key} syntax:

[[=${User:DisplayName}]]
[[=${Portal:Name}]]
[[=${Page:Title}]]

These tokens pull values from the DNN context — the logged-in user, the current portal, the page, etc. They work anywhere inside an expression, including as function arguments and in conditionals:

html
<!-- Personalized greeting -->
<p>[[=If(${User:DisplayName} = '', 'Welcome, Guest!', Concat('Hello, ', ${User:DisplayName}, '!'))]]</p>

<!-- Conditional content for logged-in users -->
<span>[[=If(${User:ID} > 0, 'Member', 'Visitor')]]</span>

Available System Tokens

TokenDescriptionExample
${User:ID}User ID (0 for anonymous)1
${User:DisplayName}Display nameKelly Ford
${User:Email}Email address[email protected]
${User:Username}Login usernamehost
${User:FirstName}First nameKelly
${User:LastName}Last nameFord
${Portal:ID}Portal ID0
${Portal:Name}Portal nameMy Website
${Portal:HomeDirectory}Portal home directory pathPortals/0/
${Module:ModuleID}Current module ID386
${Module:TabID}Current page/tab ID42
${Module:PortalID}Module's portal ID0
${Page:ID}Current page ID42
${Page:Name}Page nameProducts
${Page:Title}Page titleOur Products
${Page:FullUrl}Full page URLhttps://example.com/products

Note: The ${...} syntax is used for system tokens and for field names with spaces. XMod Pro tells them apart by the colon — ${User:DisplayName} is a system token, while ${First Name} is a field reference.

Operators

Arithmetic Operators

OperatorDescriptionExample
+Addition (or string concatenation)Price + Tax
-SubtractionTotal - Discount
*MultiplicationPrice * Quantity
/DivisionTotal / Count
%Modulo (remainder)Index % 2

String Operator

OperatorDescriptionExample
&String concatenationFirstName & ' ' & LastName
+String concatenationFirstName + ' ' + LastName

The & operator always concatenates as strings. The + operator adds numbers but concatenates if both values are non-numeric strings.

Comparison Operators

OperatorDescriptionExample
=EqualStatus = 'Active'
!=Not equalCategory != 'Hidden'
<>Not equal (VB style)Category <> 'Hidden'
>Greater thanPrice > 100
<Less thanQty < 5
>=Greater than or equalScore >= 90
<=Less than or equalAge <= 18

String comparisons are case-insensitive: 'Hello' = 'hello' is True.

Logical Operators

OperatorDescriptionExample
AndBoth must be truePrice > 10 And Qty > 0
OrEither must be trueRole = 'Admin' Or Role = 'Editor'
NotInverts a conditionNot IsHidden

Operator Precedence

When an expression has more than one operator, XMod Pro needs to decide which operation to perform first. This is called operator precedence — it works the same way as the order of operations you learned in math class (multiplication before addition, etc.).

For example, consider this expression:

[[=Price + Tax * Quantity]]

You might expect this to add Price and Tax first, then multiply. But because multiplication has higher precedence than addition, XMod Pro actually calculates Tax * Quantity first, then adds Price. If Tax is 5, Quantity is 3, and Price is 100, you'd get 100 + (5 * 3) = 115, not (100 + 5) * 3 = 315.

Use parentheses to control the order explicitly:

[[=(Price + Tax) * Quantity]]

When in doubt, add parentheses — they make your intent clear and prevent surprises.

Precedence Table

From highest (evaluated first) to lowest (evaluated last):

PrecedenceOperatorsDescription
1 (highest)- (negative sign)Negation
2* / %Multiplication, division, modulo
3+ - &Addition, subtraction, concatenation
4= != <> > < >= <=Comparisons
5NotLogical NOT
6 (lowest)And OrLogical AND / OR

Functions Reference

String Functions

FunctionSyntaxDescription
UpperUpper(value)Converts to UPPERCASE
LowerLower(value)Converts to lowercase
TrimTrim(value)Removes leading/trailing whitespace
LeftLeft(value, n)Returns the first n characters
RightRight(value, n)Returns the last n characters
LenLen(value)Returns the string length
ReplaceReplace(value, old, new)Replaces all occurrences of old with new
TruncateTruncate(value, n, suffix)Truncates to n characters and appends suffix
UrlEncodeUrlEncode(value)URL-encodes for use in query strings
HtmlEncodeHtmlEncode(value)HTML-encodes special characters
CoalesceCoalesce(v1, v2, ...)Returns the first non-null, non-empty value
ConcatConcat(v1, v2, ...)Joins all values into one string
FormatSee below.NET format strings

Format Function

Format has two modes:

Value formatting — format a single value with a .NET format specifier:

[[=Format(Price, 'C2')]]       → $19.99
[[=Format(Percent, 'P0')]]     → 85%
[[=Format(EventDate, 'MMM d, yyyy')]]  → Jan 15, 2026

Uses .NET format strings. Common format specifiers:

  • C2 — Currency with 2 decimal places
  • N0 — Number with commas, no decimals
  • P1 — Percentage with 1 decimal
  • d — Short date
  • MMM d, yyyy — Custom date format

Positional placeholders — build a string with {0}, {1}, etc.:

[[=Format('Hello {0}!', Name)]]           → Hello Kelly!
[[=Format('{0} of {1}', City, State)]]    → Portland of Oregon
[[=Format('{0}: {1} units', Product, Qty)]]  → Widget: 42 units

Uses {0}, {1}, etc. as placeholders for the remaining arguments. This is useful when you need to combine fields with specific formatting in a single token.

How does XMod Pro choose? If the first argument contains {0}, it uses positional placeholders. Otherwise, it uses value formatting. This means Format(Price, 'C2') works as expected (the format specifier C2 doesn't contain {0}), and Format('Total: {0}', Price) also works as expected.

Math Functions

FunctionSyntaxDescription
RoundRound(value, decimals)Rounds to decimals places
FloorFloor(value)Rounds down to nearest integer
CeilingCeiling(value)Rounds up to nearest integer
AbsAbs(value)Returns absolute (positive) value
MinMin(a, b)Returns the smaller value
MaxMax(a, b)Returns the larger value

Conditional Function

FunctionSyntaxDescription
IfIf(condition, trueVal, falseVal)Returns trueVal when condition is true, falseVal otherwise
IfIf(condition, trueVal)Returns trueVal when true, empty string when false

Nest If calls for multiple conditions:

[[=If(Score >= 90, 'A', If(Score >= 80, 'B', If(Score >= 70, 'C', 'F')))]]

System Functions

FunctionSyntaxDescription
NowNow()Current date and time
TodayToday()Current date (midnight)
[[=Format(Now(), 'MMMM d, yyyy')]]  → January 15, 2026

String Literals

String literals use single quotes only:

[[=If(Status = 'Active', 'Yes', 'No')]]

Double quotes are not supported inside expressions because XMP templates live inside HTML attributes that already use double quotes. Single quotes avoid this conflict.

Working with Null Values

When a field is null or DBNull:

  • String operations treat it as an empty string ""
  • Arithmetic operations treat it as 0
  • Conditional checks treat it as false

Use Coalesce to provide fallback values:

[[=Coalesce(Phone, 'Not provided')]]

Use If to check before using a value:

[[=If(ImageUrl, Concat('<img src="', ImageUrl, '">'), '')]]

What Counts as True or False?

ValueTrue or False?Notes
TrueTrueA boolean true is always true
FalseFalseA boolean false is always false
"True"TrueA non-empty string that is not "False" or "0"
"False"FalseSpecial handling for the text "false" (case-insensitive)
Non-zero number (1, 42, -3)TrueIncludes negative numbers
Non-empty string ("hello")TrueAny text but "0" or "false"
Zero (0)FalseNumeric value 0 is false
"0"FalseSpecial handling for string representation of zero
Empty string ("")FalseSame as a field with no value
Null / DBNullFalseMissing or undefined fields

Common Patterns

Price Calculations

html
<!-- Price with tax -->
<td>[[=Format(Round(Price * 1.0825, 2), 'C2')]]</td>

<!-- Discount badge -->
<span class="discount">[[=Round((1 - SalePrice / RegularPrice) * 100, 0)]]% off</span>

<!-- Line total -->
<td>[[=Format(UnitPrice * Quantity, 'C2')]]</td>

Conditional Styling

html
<!-- CSS class based on data -->
<tr class="[[=If(IsActive, 'active', 'inactive')]]">

<!-- Show/hide elements -->
<span class="badge [[=If(QtyInStock > 10, 'bg-success', If(QtyInStock > 0, 'bg-warning', 'bg-danger'))]]">
  [[=If(QtyInStock > 10, 'In Stock', If(QtyInStock > 0, 'Low Stock', 'Out of Stock'))]]
</span>

String Formatting

html
<!-- Full name from parts -->
<span>[[=Concat(FirstName, ' ', LastName)]]</span>

<!-- Initials -->
<div class="avatar">[[=Concat(Upper(Left(FirstName, 1)), Upper(Left(LastName, 1)))]]</div>

<!-- Truncated description -->
<p>[[=Truncate(Description, 150, '...')]]</p>

<!-- Name formatting: "Smith, John" -->
<td>[[=Concat(LastName, ', ', FirstName)]]</td>

Fallback Values

html
<!-- First non-empty value -->
<span>[[=Coalesce(Nickname, FirstName, 'Anonymous')]]</span>

<!-- Default image -->
<img src="[[=Coalesce(PhotoUrl, '/images/no-photo.png')]]" />

Do's and Don'ts

Do

html
<!-- Use single quotes for strings -->
[[=If(Status = 'Active', 'Yes', 'No')]]

<!-- Use & for explicit string concatenation -->
[[=FirstName & ' ' & LastName]]

<!-- Use Coalesce for null-safe defaults -->
[[=Coalesce(Email, 'none')]]

<!-- Nest functions freely -->
[[=Upper(Trim(Left(Name, 20)))]]

Don't

html
<!-- DON'T use double quotes (won't work) -->
[[=If(Status = "Active", "Yes", "No")]]

<!-- DON'T nest expression tokens -->
[[=Upper([[=Lower(Name)]])]]

<!-- DON'T use in data commands or data sources -->
<xmod:SqlCommand CommandText="SELECT [[=Upper(Name)]]" />
<ListDataSource CommandText="SELECT [[=Upper(Name)]] FROM ..." />

<!-- DON'T use assignment -->
[[=Price = 19.99]]

Limitations

  1. No nesting of [[=...]] tokens. Use function nesting instead: [[=Upper(Trim(Name))]]
  2. Not available in data commands. Expression tokens are not processed inside CommandText attributes on data commands (<xmod:SqlCommand>) or data sources (<ListDataSource>, <DetailDataSource>, <xmod:SqlDataSource>, etc.). Use SQL functions in your queries instead.
  3. No assignment. Expression tokens are read-only — = is the equality operator, not assignment.
  4. Single quotes only. Double quotes are not supported inside expressions.
  5. No access to other server controls. Expression tokens evaluate against the current data row only.

Expression Tokens vs. Function Tokens

XMod Pro also has Function Tokens (like [[Join(...)]]) which have been available since earlier versions. Expression tokens are more powerful and flexible — they support math, conditionals, and a much larger set of functions. However, function tokens like [[Join(...)]] and [[Localize:keyName]] still work. [[Join()]] may be deprecated in the future as we think [[=Format()]], [[=Concat()]] and [[=Coalesce()]] provide much more flexibility and readability. We encourage you to try them instead of Join. [[Localize]] is not deprecated.