Template modes¶
Sometimes a single pass over the document is not enough. You may need to walk the
same nodes more than once and render them differently each time — a compact
table of contents up top, then the full details below. Both passes select the
same <cd> elements, but one should emit a one-line title and the other a full
row. A plain match="cd" template can only do one of those things.
Modes solve this. A template can be tagged with a mode, and only an
apply-templates that asks for that same mode will reach it. The same source
element can therefore have several templates — one per mode — each producing its
own output.
The problem: one element, two renderings¶
Suppose you want both an index of titles and a detail listing. Without modes a
second <xsl:template match="cd"> would simply override the first — you cannot
have two unrelated rules for the same pattern in the same mode.
A mode is a tag on the rule¶
Add mode="x" to a template, and add the matching mode="x" to the
apply-templates that should reach it.
- The same
cdnodes, selected a first time inmode="toc". - The same nodes again, this time in
mode="detail". - This template is considered only when something applies templates in
mode="toc". It is invisible to thedetailpass and to the default mode. - A second rule for the very same
match="cd"pattern — legal, because it lives in a different mode. No clash with thetocrule above.
The catalog was traversed twice. Each <cd> matched a different template
purely because the two apply-templates calls asked for different modes.
Modes are independent namespaces of rules¶
A mode partitions your templates into separate worlds:
apply-templateswithmode="toc"only ever considers templates that carrymode="toc".apply-templateswith nomodeuses the default (unnamed) mode and considers only templates that have nomodeattribute.
So a rule in one mode is completely invisible from another. You can have
match="cd" in the default mode, in mode="toc", and in mode="detail", and
they never interfere — each fires only when its own mode is in play.
The default mode is just the unnamed one
There is nothing special about modes versus "no mode": the default is simply
the mode with no name. Writing mode="detail" on both the rule and the call
above, then dropping the attribute from both, would put that pass back in the
default mode with identical results.
Built-in templates carry the mode down¶
XSLT's built-in templates — the ones that recurse into children when you have not
written a matching rule — preserve the current mode as they descend. If you
apply templates in mode="toc" to an element you have not given a toc
template, the built-in rule still fires, and it keeps recursing in toc
mode, looking for toc templates on the descendants.
| inherited-mode.xsl | |
|---|---|
- No rule matches
catalogorcdinmode="toc", so the built-in template handles them — and it descends still intocmode. - Only when recursion reaches a
<title>does an explicittocrule fire.
Forgetting the mode silently does nothing useful
If you write a mode="detail" template but call apply-templates without
mode, the default built-in rules run instead — they ignore your detail
template entirely and just spit out text content. A pass that produces only
whitespace or raw text is almost always a missing or mismatched mode.
Modes versus named templates¶
Both modes and named templates let one element be handled more than one way, but they pull in opposite directions:
- Modes are still the push model:
apply-templates ... mode="x"selects and moves to each node, and the matching mode rule runs with that node as the current node. Use a mode when you are walking node-sets and want a different rendering of the same nodes. - Named templates are the call model:
call-template name="x"runs in the caller's context and does not move the current node. Use a name for reusable, parameterised logic that is not "one template per node".
XSLT 2.0 / 3.0 mode tokens
Later versions add convenience tokens to apply-templates/xsl:template:
mode="#default" refers to the default mode explicitly, and mode="#all" on a
template makes it apply in every mode. In 1.0 you simply name each mode and
repeat the rule where you need it.
Next¶
Once a stylesheet grows several modes and shared rules, you will want to split it
into pieces and pull them together. Reusing stylesheets covers
xsl:include and xsl:import so common templates live in one place.