Sessel expression binding

A Sessel expression binding evaluates a Sessel expression during server-side composition and exposes the result as a named variable to templates. For the JavaScript peer, see JavaScript expression binding.

When to reach for it

Use expression bindings to compute values — averages, filtered lists, counts — directly in HTML without application code. They complement resource bindings, which select elements but cannot compute over them.

Namespace declaration

Declare the Sessel binding namespace on an ancestor element:

<html xmlns:e="https://pagelove.org/Binding/Sessel">

The namespace URI must be exactly https://pagelove.org/Binding/Sessel. The prefix (here e) can be any valid XML prefix.

Attribute form

Part Role
Prefix (e:) The declared namespace prefix
Attribute name The variable name exposed to templates
Attribute value A Sessel expression evaluated at serve time
<div e:total="${[itemprop="price"]}.sum()"
     e:count="${[itemprop="price"]}.count()"
     pagelove:template="text/liquid">
  <p>{{ count }} products totalling ${{ total }}</p>
</div>

Declaration-order evaluation

Attributes evaluate left to right in source order. A bound name is available to subsequent expressions on the same element:

<div e:total="${[itemprop="price"]}.sum()"
     e:count="${[itemprop="price"]}.count()"
     e:average="total / count"
     pagelove:template="text/liquid">
  <p>Average price: ${{ average }}</p>
</div>

Here total and count resolve first. When average evaluates, both names are already in scope.

Scope

Bindings follow element ancestry:

<section xmlns:e="https://pagelove.org/Binding/Sessel"
         e:sitecount="${div.item}.count()">

  <!-- sitecount is available here and in all descendants -->
  <div e:localcount="${div.item} from self).count()"
       pagelove:template="text/liquid">
    <!-- Both sitecount and localcount are available -->
    <p>{{ localcount }} of {{ sitecount }} items</p>
  </div>

  <div pagelove:template="text/liquid">
    <!-- sitecount is available, localcount is NOT (it is on a sibling) -->
    <p>{{ sitecount }} total items</p>
  </div>

</section>

The three bindings compared

Sessel is one of three binding namespaces that attach a named value to an element during composition:

Aspect Resource binding Sessel expression binding JavaScript expression binding
Namespace https://pagelove.org/Binding/CSS https://pagelove.org/Binding/Sessel https://pagelove.org/Binding/JavaScript
Value CSS selector (returns matching elements) Sessel expression (returns any value) JavaScript expression (returns any value)
Can compute No — selects elements only Yes — arithmetic, aggregation, filtering Yes — full JavaScript expression
Can reference other bindings No Yes — later bindings can reference earlier ones Yes — earlier bindings read as bare identifiers

All three may appear on the same element. Resource bindings resolve first, then expression bindings evaluate in declaration order.

Examples

Count and sum from site data

Expression bindings can aggregate values across multiple documents. Given two product pages, a summary page uses count() and sum() to compute totals:

{% example "setup-summary", "body" %}

Fetching the summary page renders the computed values:

GET /sessel-expr-summary.html
HTTP/1.1 200

<!DOCTYPE html>
<html>
<body>
  <div>
    <p>Count: 2</p>
    <p>Sum: 100.0</p>
  </div>
</body>
</html>

Error cases

Condition Result
Sessel expression fails to compile Request fails with an error during composition
Expression references an undefined variable name Request fails with an error during composition
Namespace URI is not exactly https://pagelove.org/Binding/Sessel Attributes are ignored — no bindings are created

See also