XSLT - Text Value Templates in XSLT

Text Value Templates are a feature introduced in modern XSLT that allows XPath expressions to be embedded directly inside text nodes of an XSLT stylesheet. Instead of writing separate <xsl:value-of> instructions every time a dynamic value needs to be inserted into text, you can place an expression inside curly braces {}.

The W3C XSLT 3.0 specification defines value templates as strings containing fixed text together with variable parts represented by expressions enclosed in curly braces. It distinguishes attribute value templates from text value templates. (W3C)

1. What Is a Text Value Template?

Normally, when you want to place a value from the source XML into the output, you might write:

<xsl:text>Hello, </xsl:text>
<xsl:value-of select="name"/>
<xsl:text>!</xsl:text>

This works, but it requires several XSLT instructions.

With a text value template, the same idea can be written more directly:

<xsl:text expand-text="yes">Hello, {name}!</xsl:text>

Here:

Hello, 

is fixed text, while:

{name}

is an XPath expression.

If the source XML contains:

<student>
    <name>Alice</name>
</student>

the resulting text is:

Hello, Alice!

The important point is that the expression inside {} is evaluated, and its result is inserted into the text.

2. Why Are Text Value Templates Useful?

Text value templates make XSLT stylesheets more concise and easier to read when output contains a mixture of fixed text and dynamic values.

For example, without a text value template:

<p>
    <xsl:text>Student: </xsl:text>
    <xsl:value-of select="name"/>
    <xsl:text>, Grade: </xsl:text>
    <xsl:value-of select="grade"/>
</p>

The same output can be expressed using text expansion:

<p xsl:expand-text="yes">
    Student: {name}, Grade: {grade}
</p>

The result could be:

<p>Student: Alice, Grade: A</p>

This is particularly convenient when a sentence contains several dynamic values.

3. The expand-text Attribute

The key mechanism behind text value templates is the expand-text attribute.

In XSLT 3.0, it can be used as:

<xsl:stylesheet
    version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="yes">

When expand-text="yes" is enabled at this level, descendant text nodes can use expressions enclosed in {}.

For example:

<xsl:stylesheet
    version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="yes">

    <xsl:template match="/">
        <message>
            Welcome, {student/name}!
        </message>
    </xsl:template>

</xsl:stylesheet>

If the source XML is:

<student>
    <name>John</name>
</student>

the output is:

<message>Welcome, John!</message>

The expand-text setting can also be applied to a particular element rather than the entire stylesheet.

For example:

<xsl:template match="/" expand-text="yes">
    <message>
        Welcome, {student/name}!
    </message>
</xsl:template>

According to the XSLT 3.0 specification, text nodes are treated as text value templates when they occur in the appropriate stylesheet context and an applicable expand-text="yes" setting is present. (W3C)

4. Text Value Templates and XPath Expressions

The content inside {} is an XPath expression. Therefore, you are not limited to simply selecting an element.

For example:

<p expand-text="yes">
    Total: {price * quantity}
</p>

If the XML contains:

<product>
    <price>50</price>
    <quantity>3</quantity>
</product>

the result is:

<p>Total: 150</p>

You can also use functions:

<p expand-text="yes">
    Name: {upper-case(name)}
</p>

If:

<name>alice</name>

the result is:

<p>Name: ALICE</p>

You can use conditional expressions as well:

<p expand-text="yes">
    Status: {if (marks >= 40) then 'Pass' else 'Fail'}
</p>

If marks is 75, the output becomes:

<p>Status: Pass</p>

Therefore, text value templates are not simply string substitution. The expression inside the braces is evaluated according to XPath rules.

5. Using Variables

Text value templates are particularly useful with XSLT variables.

Consider:

<xsl:variable name="company" select="'ABC Technologies'"/>

You can use the variable directly:

<message expand-text="yes">
    Welcome to {$company}
</message>

The result is:

<message>Welcome to ABC Technologies</message>

The $ identifies the variable, while the surrounding {} tells XSLT that the content should be evaluated as an expression.

Another example is:

<xsl:variable name="year" select="2026"/>

<footer expand-text="yes">
    Copyright {$year}
</footer>

Output:

<footer>Copyright 2026</footer>

6. Using Functions Inside Text Value Templates

XPath functions can be used inside the braces.

For example:

<p expand-text="yes">
    Customer: {upper-case(customer/name)}
</p>

If the source contains:

<customer>
    <name>Robert</name>
</customer>

the output is:

<p>Customer: ROBERT</p>

You can also use string functions:

<p expand-text="yes">
    Full Name: {concat(first-name, ' ', last-name)}
</p>

For:

<person>
    <first-name>John</first-name>
    <last-name>Smith</last-name>
</person>

the output is:

<p>Full Name: John Smith</p>

This allows complex expressions to be incorporated into readable output text.

7. Using Conditional Expressions

Text value templates can contain XPath conditional expressions.

For example:

<result expand-text="yes">
    {if (score >= 50) then 'Pass' else 'Fail'}
</result>

If the value of score is 75, the result is:

<result>Pass</result>

If the value is 35, the result is:

<result>Fail</result>

This can make small conditional messages much shorter than using separate <xsl:choose> instructions.

For more complicated business logic, however, traditional XSLT instructions such as <xsl:choose> may still provide better readability.

8. Multiple Expressions in One Text Node

A single text value template can contain multiple expressions.

For example:

<p expand-text="yes">
    {first-name} {last-name} has scored {marks} marks.
</p>

For:

<student>
    <first-name>Alice</first-name>
    <last-name>Brown</last-name>
    <marks>87</marks>
</student>

the output is:

<p>Alice Brown has scored 87 marks.</p>

The stylesheet contains fixed text:

has scored

and three dynamic expressions:

{first-name}
{last-name}
{marks}

This is one of the main advantages of text value templates: the resulting sentence can look almost like the final output.

9. Text Value Templates Versus <xsl:value-of>

Both techniques can produce dynamic text, but their syntax is different.

Using <xsl:value-of>:

<p>
    <xsl:value-of select="name"/>
</p>

Using a text value template:

<p expand-text="yes">
    {name}
</p>

For a sentence, the difference becomes more noticeable.

Traditional approach:

<p>
    <xsl:text>Welcome </xsl:text>
    <xsl:value-of select="name"/>
    <xsl:text> to our website.</xsl:text>
</p>

Text value template approach:

<p expand-text="yes">
    Welcome {name} to our website.
</p>

The second version is often easier to understand because the structure of the output sentence is visible directly in the stylesheet.

10. Curly Braces Have a Special Meaning

When text value templates are enabled, curly braces have a special meaning.

For example:

<p expand-text="yes">
    Hello {name}
</p>

means that {name} should be evaluated.

But sometimes you may actually want a literal curly brace in the output.

For this purpose, XSLT provides escaping rules. A doubled opening brace:

{{

represents a literal:

{

Similarly, a doubled closing brace:

}}

represents a literal:

}

For example:

<p expand-text="yes">
    Use {{name}} as a placeholder.
</p>

can produce:

<p>Use {name} as a placeholder.</p>

This distinction is important when generating text that itself contains template-like syntax.

11. Difference Between Text and Attribute Value Templates

Text value templates and attribute value templates are related, but they are not exactly the same thing.

Consider an attribute:

<a href="{url}">Visit</a>

Here {url} is an attribute value template.

For text:

<p expand-text="yes">Visit {name}</p>

{name} is a text value template.

The W3C specification describes both as forms of value templates. Attribute value templates are used in attributes specifically designated to support them, while text value templates are controlled by the expand-text mechanism. (W3C)

This distinction matters because not every XSLT attribute automatically treats {} as an XPath expression. The XSLT specification explicitly notes that only attributes designated as attribute value templates interpret curly-braced expressions in this way. (W3C)

12. Complete Example

Consider the following XML:

<employee>
    <name>David</name>
    <department>IT</department>
    <salary>60000</salary>
</employee>

An XSLT 3.0 stylesheet can use text value templates as follows:

<xsl:stylesheet
    version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="yes">

    <xsl:output method="html" indent="yes"/>

    <xsl:template match="/">
        <html>
            <body>
                <h1>Employee Information</h1>

                <p>Name: {employee/name}</p>

                <p>Department: {employee/department}</p>

                <p>Annual Salary: {employee/salary}</p>

                <p>
                    Employee {employee/name}
                    works in the {employee/department}
                    department.
                </p>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

The generated HTML will contain content similar to:

<html>
    <body>
        <h1>Employee Information</h1>

        <p>Name: David</p>

        <p>Department: IT</p>

        <p>Annual Salary: 60000</p>

        <p>
            Employee David works in the IT department.
        </p>
    </body>
</html>

Notice how the stylesheet closely resembles the desired output.

13. Local expand-text Control

You do not always have to enable text expansion for the entire stylesheet.

For example:

<xsl:template match="/">
    <message expand-text="yes">
        Hello {employee/name}
    </message>
</xsl:template>

Only the relevant area needs text expansion.

This can be useful when a stylesheet contains literal text that includes curly braces and should not be interpreted as XPath expressions.

The XSLT specification allows expand-text to control whether descendant text nodes are interpreted as text value templates. (W3C)

14. Important Difference Between {} and $

Beginners sometimes confuse the roles of {} and $.

Consider:

<xsl:variable name="name" select="'Alice'"/>

Then:

<p expand-text="yes">Hello {$name}</p>

Here:

$

means that name is an XSLT variable.

The surrounding:

{}

means that the expression should be evaluated as part of the text value template.

Therefore:

{$name}

means "evaluate the variable named name and insert its value here."

Similarly:

<p expand-text="yes">Total: {price * quantity}</p>

contains an XPath expression rather than a variable.

15. Common Mistakes

Mistake 1: Forgetting expand-text

This may not behave as expected:

<p>Hello {name}</p>

if text value templates have not been enabled in the relevant context.

A safer explicit form is:

<p expand-text="yes">Hello {name}</p>

Mistake 2: Treating every {} as an XSLT expression

Curly braces are only interpreted as text value templates when the relevant text node has been designated for text expansion.

Mistake 3: Confusing text templates with attribute templates

This:

<a href="{url}">

is an attribute value template.

This:

<p expand-text="yes">Visit {name}</p>

uses a text value template.

They are related mechanisms but operate in different contexts.

Mistake 4: Putting complex logic everywhere

Although text value templates can contain XPath expressions, very complicated expressions can make a stylesheet difficult to maintain.

For example, instead of placing a very long conditional expression directly inside text, it may be better to calculate the value in a variable:

<xsl:variable name="status"
              select="if (score >= 50) then 'Pass' else 'Fail'"/>

<p expand-text="yes">
    Result: {$status}
</p>

This separates calculation from presentation.

16. Advantages of Text Value Templates

Text value templates provide several practical advantages.

Improved readability: The stylesheet can resemble the final text that will be generated.

Less verbose code: Simple <xsl:value-of> instructions can often be replaced with inline expressions.

Easy combination of static and dynamic content: Several XPath expressions can be placed inside the same sentence.

Better maintainability: Text-heavy transformations can become easier to read and modify.

Power of XPath: Since the content inside {} is an XPath expression, functions, calculations, variables, conditions, and other XPath capabilities can be used.

17. When Should You Use Text Value Templates?

Text value templates are especially useful when generating:

  • HTML paragraphs

  • Messages

  • Labels

  • Reports

  • Text documents

  • XML text content

  • Dynamic descriptions

  • Log messages

  • Notification content

  • Human-readable summaries

For example:

<p expand-text="yes">
    Order {order/@id} was placed by {order/customer}
    for a total of {order/total}.
</p>

This is much easier to read than constructing the same sentence from multiple <xsl:text> and <xsl:value-of> instructions.

18. Summary

Text Value Templates provide a concise way to insert dynamically calculated values into text generated by an XSLT stylesheet. They use curly braces to identify XPath expressions and rely on expand-text="yes" to enable this behavior for stylesheet text nodes. (W3C)

The basic pattern is:

<element expand-text="yes">
    Static text {XPath expression} more static text
</element>

For example:

<p expand-text="yes">
    Welcome, {name}. Your score is {score}.
</p>

If the source XML contains:

<student>
    <name>Alice</name>
    <score>95</score>
</student>

the result is:

<p>Welcome, Alice. Your score is 95.</p>

The main idea is simple: fixed text remains fixed, while expressions inside {} are evaluated and inserted into the resulting text. This makes text-heavy XSLT transformations considerably more compact and readable. (W3C)