Skip to content

Chapter 11: Conditional formatting

Introduction

WARNING - this is an advanced topic, intended for programmers trying to deal with difficult layout cases. The tags documented here have the potential to cause hard-to-understand exceptions if not used correctly!

Conditional formatting allows you to include expressions in your RML text which are evaluated or executed when the pdf is actually being built. This means that you can vary the content of your document depending on conditions (such as where you are on the page) which you do not know in advance.

For instance, you may be including dynamic content in your document which is likely to be of variable length. You could use the value of one of the document's internal formatting variables to include or exclude certain content, based on the remaining height of a page or the current page number. One common use is in the case of creating documents for printing: these could be 'padded out' with optional content, to make sure that they are always a 4-page spread. Another useful application would be deciding whether there is space to include a large image or diagram in the present location.

A working example using all of these tags can be found in rlextra/rml2pdf/test/test_039_doc_programming.rml.

Basic programming primitives (assignment, loop, if, while etc.) have been made available as tags. These can be given expressions which can use your own variables, as well as built-in ones available during rendering. All expressions must be valid python literal expressions.

The following internal variables are available to use as conditions:

availableWidth and availableHeight give you the remaining height and width of the current frame.

doc.frame.id returns the id of the current frame

doc.pageTemplate.id returns the id of the current page template

doc.page returns the current page number.

Tags

The <docIf>, <docElse> and <docWhile> tags allow you to control which content is included and excluded - while, or if, a condition is true or false.

The <docPara> tag allows you to include the value of an expression in the output text. This is useful for debugging document layouts (e.g. temporarily inserting paragraphs like "you are [3] inches down the [left] frame of the [chapter_first_page] template on page [19]"), but you can also use it to display facts you stored earlier. The value can be formatted using Python format strings - see the test case above for details.

<docAssign> assigns a value to a variable, and <docExec> executes a statement or expression.

The <docAssert> tag allows you to test an expression and raise an exception if it is not true. This can be a useful quality assurance technique. As with the docPara example for debugging, you can include assertions like "I should now be at the top of page 3" or "I should now be in the footer frame".

Operators

When using docIf or docWhile tags, you can use the following operators to evaluate your conditions:

= < <= > => %

However, bear in mind that the 'greater than' and 'less than' operators must be written in RML as &gt; and &lt;

Examples

Some sample code demonstrating several of the conditional formatting tags:

<docAssign var='i' expr="3"/>
<docIf cond='i&gt;2'>
    <para style="normal">The value of i is greater than 2</para>
    <docElse/>
    <para style="normal">The value of i is less than or equal to 2</para>
</docIf>
<docWhile cond='i'>
    <docPara expr='i' format='The value of i is %(__expr__)d'/>
    <docExec stmt='i-=1'/>
</docWhile>

results in the output:

The value of i is greater than 2
The value of i is 3
The value of i is 2
The value of i is 1

As an example of a practical use of conditional formatting, supposing you wanted all your documents to be a certain number of pages. You could use the value of doc.page to decide whether to include or exclude an external 'filler' pdf in your output, and so pad the size of your document:

<docIf cond="doc.page == 3">
    <includePdfPages filename="fillerpage.pdf" pages="1" leadingFrame="yes"/>
</docIf>

Reference

Conditional formatting is implemented with the following tags:

<docAssign var='' expr=''>

assigns the value of 'expr' to 'var', eg to make i=3 : <docAssign var='i' expr='3'/>

<docExec stmt=''>

executes the statement 'stmt', eg to subtract 1 from the value of i : <docExec stmt='i-=1'/>

<docPara expr='' format='' style=''>

creates a paragraph containing the value of 'expr'.

'format' is an optional attribute which can contain the value of 'expr' using the Python string formatting conventions, eg "%(expr)s".

The 'style' attribute is optional.

eg: <docPara expr='i' format='The value of i is %(expr)d' style="style.txt"/>

So if i=2, this results in the text "The value of i is 2"

<docAssert cond='' format=''>

raises an error containing the value of 'format' if 'cond' is false, eg:

eg: <docAssert cond='val', format="val is false" />

<docWhile cond=''>

<docIf cond=''>

<docElse>

these tags allow flow control while or if the 'cond' attribute evaluates to true. See the example above.