Beyond expressions, statements are the second type of POD constructs allowing to tailor a part of some ODT template.
4 types of statements exist:
- the if statement,
- the else statement,
- the for statement,
- the with statement.
The if statement allows to conditionnaly include a part of an ODT document, depending on the evaluation of the tied Python expression. The else statement allows to conditionnaly include a part of an ODT statement depending on the negation of the evaluation of the previous if statement. The for statement allows to repeatedly include a portion of an ODT document, based on a sequence of data specified in the statement. The with statement allows to define a variable, whose scope will be the statement's target.
The « if » statement
An if statement is written in an ODT comment and has the form
do <document_part> if <python_expression>
The <document_part> is the target of the statement and will only be included in the result if the <python_expression> resolves to True (the boolean value, or any equivalent Python value, like a non empty list, string, etc). "Document parts" that can be referenced in "if" statements, as well as in any other statement type, are presented in the table below.
Name | Description |
---|
text |
A paragraph of standard text |
title |
A title |
section |
A section |
table |
A table |
row |
A single row within a table |
cell |
A single cell within a table row |
frame |
A (floating) frame |
item |
An item within a numbered or bulleted list of items. |
doc |
The whole document. Consult this section for more info. |
The « else » statement
An else statement refers to the condition of the previous if statement, and has the form:
do <document_part> else
More information about this statement can be found in the page dedicated to it.
The « for » statement
A for statement, also written in an ODT comment, has the form
do <document_part> for <variable_name> in <python_expression>
The <document part>, which is the target of the statement, will be included as many times as there are items in the sequence that is defined by the <python_expression>. Within the document part in question, one can use <variable_name>, or any Python expression that uses it, within inner expressions or statements (the for statement adds this name in the context). Allowed <document_part>s are those described in the previous table. If <variable_name> was already defined in the context, it is hidden by this new variable definition only within the scope of the targeted <document_part>.
The « with » statement
A with statement defines a variable that can be used in the scope defined by the element being the statement target. This statement has the form:
do <document_part> with <variable_name> = <python_expression>
Such a variable behaves similarly to any entry given in the original context, excepted that it can only be used within the scope of the ODT element being the target of the variable definition.
An example
The example below illustrates the use of if, for and else statements.
Inserting a comment in LibreOffice is done via menu Insert > Comment, or shortcut CTRL+ALT+C.
Let's define the following context to illustrate how the previous template can be rendered.
class Person:
def __init__(self, name):
self.name = name
self.lastName = '%s last name' % name
self.firstName = '%s first name' % name
self.address = '%s address' % name
class Group:
def __init__(self, name):
self.name = name
if name == 'group1':
self.persons = [Person('P1'), Person('P2'), Person('P3')]
elif name == 'group2':
self.persons = [Person('RA'), Person('RB')]
else:
self.persons = []
groups = [Group('group1'), Group('group2'), Group('group3')]
Applying this context to the POD template will produce this result.
The POD template contained a single section. The result contains 3 sections, whose content varies, depending on the evaluation of its inner POD expressions and statements. The presence of 3 sections in the POD result is the effect of the first comment, that has repeated the section, as many times as there are groups in the list named groups, present in the POD context. Within each such section, the for statement has added variable group in the context. This variable is first used by the inner expression group.name, to render the name of the group just before the table. The same variable is then used in the following if statement, that determines if the table of persons is rendered or not, depending on the presence of people (in attribute group.persons). For the 2 first groups, the table has been rendered, but not for the third, empty group. For this latter, an else statement, using the negation of the previous if statement, renders the paragraph announcing that there is nobody in this group.
Within each rendered table, an inner for statement renders as many table rows as there are persons in the group. Inner expressions render, in each row, the person's attributes, like his first name, last name and address.
Guidelines
When starting to write POD statements within LibreOffice comments, follow these guidelines.
- Pay attention to LibreOffice's automatic replacements. Typically, when starting to write, in a comment, text like "do text ...", LibreOffice will upperize the first char: "Do text ...". Replace it afterwards by a lowercase letter again.
- Automatic replacements also occur with quotes. Standard single or double quotes written down in comments may be replaced with "nice" quotes, that will produce syntax errors when the Python interpreter will evaluate parts of your statements. If you cannot copy/paste quotes from another comment, I recommand using the "Find" function from LibreOffice, where automatic replacements are disabled. Use menu Edit > Find... or type CTRL-F: the "Find" field will appear. Type your quote in it, then, copy and paste it to your comment.
- Similar problems may also occur with blanks, that could be converted to non-breaking spaces for example. So when writing a Python expression, use blanks only at places where it is essential. For example, in the following expression, write down the list without any blank between its values: do text for char in ['a','p','p','y']. Do not write it like this: ['a', 'p', 'p', 'y'].
- At the time I wrote these lines, the size of the comment zones in LibreOffice are of fixed size. If the content of your statement is large, use a narrow font like Ubuntu Condensed. That way, you maximize the portion of your statement that will be visible without scrolling.
- Try to minimize Python code within POD templates. POD templates should be as readable as possible. Non-developers may need to consult them. So try minimize the amount of Python code you put in it. For example, instead of writing a complex expression or a complex condition within a statement, think about writing this code in a Python method with a nice name and simply call it within your template (of course the object on which this method is defined must be in the POD context). If you need to use the result of a resources-consuming method in several places within a POD template, instead of calling this method in several expressions (POD will execute the method in each expression), call it once before rendering the template and give the result under a new name in the context passed to POD.
- Where exactly can you place statements ? You can place them anywhere within the element you want to repeat or conditionally include. In the POD template above, the first statement, whose target is a section, is placed at the end of the first title present in the section. In a table, for example, you can place a "do table..." statement in any cell of the table (by the way, it is technically impossible to place a statement, within a table, outside any cell). The only thing you have to take care of is the order of statements applying on nested elements. For example, a statement applying on a table must be placed in the table before a second one that would apply on a row of this table. This statement must itself be placed before another one applying on a cell within that row. In the first cell of a table, for example, you can define several statements sequentially: one for the table, one for the row and one for the cell.