Skip to content
Variables

Variables

All variables in XTS are globally visible by default. This is intentional – since XTS executes layout code as it builds the PDF (including page hooks like <AtPageShipout>), variables must be accessible everywhere. The exception is parameters inside a <Function> or <Template>, which are scoped to the body.

Setting variables

<SetVariable variable="count" select="42"/>
<SetVariable variable="name" select="'hello'"/>

Reading variables

Use $variablename in XPath expressions:

<Value select="$count"/>
<Message select="concat('Name is: ', $name)"/>

Storing complex content

Variables can hold not just simple values but entire XML structures:

<SetVariable variable="greeting">
    <Paragraph>
        <Value>Hello, world!</Value>
    </Paragraph>
</SetVariable>

<PlaceObject>
    <TextBlock>
        <Value select="$greeting"/>
    </TextBlock>
</PlaceObject>

A practical use case is storing table column definitions for reuse:

<SetVariable variable="tablecolumns">
    <Columns>
        <Column width="1cm"/>
        <Column width="4mm"/>
        <Column width="1cm"/>
    </Columns>
</SetVariable>

<Table>
    <Value select="$tablecolumns"/>
    <Tr>...</Tr>
</Table>

Appending to variables

Build up content incrementally:

<SetVariable variable="foo">
    <Value>Hello</Value>
</SetVariable>

<SetVariable variable="foo">
    <Value select="$foo"/>
    <Value>, world!</Value>
</SetVariable>
<!-- $foo is now "Hello, world!" -->

This also works for building XML structures:

<SetVariable variable="toc">
    <Value select="$toc"/>
    <Element name="entry">
        <Attribute name="title" select="@name"/>
        <Attribute name="page" select="sd:current-page()"/>
    </Element>
</SetVariable>

Evaluation time

Variable contents with child elements are evaluated immediately when <SetVariable> is executed. So this:

<SetVariable variable="greeting"><Value>nice</Value></SetVariable>
<SetVariable variable="tmp"><Value select="$greeting"/></SetVariable>
<SetVariable variable="greeting"><Value>cruel</Value></SetVariable>
<!-- $tmp is still "nice" -->

This means variables must not contain output commands like <PlaceObject> – those would execute immediately during assignment. Declaring the variable’s type with as makes this a checked rule rather than a silent trap: see Values and types and Data vs. action.

Collections

For lists and dictionaries, use XPath’s built-in arrays and maps rather than juggling many variables – they are real values you can store, nest, query, and pass around:

<SetVariable variable="nums" select="[10, 20, 30]"/>
<SetVariable variable="prices" select="map { 'apple': 30, 'pear': 45 }"/>

<Value select="$nums?2"/>        <!-- 20 -->
<Value select="$prices?apple"/>  <!-- 30 -->

See Maps and arrays for the full story.

Dynamic variable names

The variable name itself can be computed, which is occasionally useful when the name depends on the data:

<SetVariable variable="{ concat('item', 1) }" select="'First'"/>
<SetVariable variable="{ concat('item', 2) }" select="'Second'"/>

<!-- Read back: sd:variable() joins its arguments into a name and returns the value -->
<Message select="sd:variable(('item', 1))"/>
<Message select="sd:variable(('item', 2))"/>

Reach for this only when you genuinely need dynamically named global variables. For ordinary collections, a map or array is clearer and keeps the data in one value.

See also