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
- Maps and arrays – arrays, maps, and the
?lookup operator. - Values and types – typing a variable with
asand the queryable data band. - Functions – parameterised, reusable values.
- Templates – parameterised, reusable behaviour.