Variables and Functions
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.
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.
Simulating arrays
XTS doesn’t have built-in arrays, but you can simulate them with dynamic variable names:
<SetVariable variable="{ concat('item', 1) }" select="'First'"/>
<SetVariable variable="{ concat('item', 2) }" select="'Second'"/>
<!-- Read back -->
<Message select="sd:variable(('item', 1))"/>
<Message select="sd:variable(('item', 2))"/>The sd:variable() function concatenates its arguments into a variable name and returns the value.
Functions
You can define custom functions in the layout file:
<Layout xmlns="urn:speedata.de/2021/xts/en"
xmlns:sd="urn:speedata.de/2021/xtsfunctions/en"
xmlns:fn="mynamespace">
<Record match="data">
<Message select="fn:add(4, 3)"/>
</Record>
<Function name="fn:add">
<Param name="first"/>
<Param name="second"/>
<Value select="$first + $second"/>
</Function>
</Layout>Output: 7.000000
Key points:
- The function namespace (
fn:in this example) must be declared on the root element. - Parameters are accessed as local variables (
$first,$second). - Variables inside functions have local scope (unlike the rest of XTS).
- Every
<Value>in the function body contributes to the return value. - Functions can output objects too, not just return values.
Functions returning XML
Functions can build and return XML structures:
<Function name="fn:cols">
<Param name="colspec"/>
<Columns>
<ForAll select="$colspec">
<Column width="{.}"/>
</ForAll>
</Columns>
</Function>
<!-- Call with a sequence -->
<Table>
<Value select="fn:cols(('2cm', '3cm'))"/>
<Tr>
<Td><Paragraph><Value>two cm</Value></Paragraph></Td>
<Td><Paragraph><Value>three cm</Value></Paragraph></Td>
</Tr>
</Table>The curly braces {.} switch into XPath mode, where . is the current item in the <ForAll> iteration.