ODF and PDF formats.
The data to be included in the report will be extracted from the database through queries.ODT (text, tables, images...) objects.
A portion of a report may not define a model; useful in the case when you want to define a data query to be used in successive portions.
A portion of a report may also not define a query; in this case, the model will only be applied once.DTL is used; which is a specific language for processing of templates (template processing), very versatile and widespread in various environments, such as Perl and Dojo Toolkit, which are both used in MasonSQL.
The report generator uses the Perl DTL::Fast library which implements specific parts of the DTL language.
With respect to official implementation, there are some compatibility issues and extensions that we cite only for some sophisticated users of the language.
In DTL, the characters {{ and }} are used to delimit the text to be interpreted.var variable, you would write {{ var }} in the template or in the query.
The variables present in DTL can also be regrouped in a hierarchical fashion, using hashes and arrays.{{ myhash.mykey }} wherein myhash is the name of the hash and mykey is the name of the key.
DTL.
The parameters are inserted in a hash named ARGV (ARGument Variables) which will be visible in all templates and queries.
For instance, if you use the generator with the following parameters, param1=100 MyPAR='my string data', they will be available in DTL as {{ ARGV.param1 }} and {{ ARGV.MyPAR }}.
query in SQL with which, will retrieve data from the database.
In the query, we can insert the DTL constructs, which are processed before in every execution to extract the data table.
For each row of data retrieved, the portion using the template will be generated (if present), rendering visible the data from the columns with DTL variables.
The data from each row will be visible in DTL as hash; for instance, if the portion is named HEAD, the data from the row will be of the type {{ HEAD.var }}.
In case of fields of JSON type, the field content will be converted to hash or array so it will be possible to refer to the underlying data like {{ HEAD.myhash.myfield }} {{ HEAD.myarray[5] }}
The DTL hash will have additional entry ROW_NUMBER which will tell the recordset row number, staring with 1. For example the tag {{ HEAD.ROW_NUMBER }} will be replaced by the current row number.
The hash, thusly defined, will also be visible in the successive processing of the queries and the templates of portions at the same level or higher.
SQL table, using bytea format.
An image in the portion will be rendered only when its name contains a DTL tag. The format of the name will be: #<portion_name>.<image_field_name>. The images without DTL tag will be ignored.
Rendered template images will be replaced with the appropriate images from the database.
Format of the image names, added to the report, will be: <portion name>_<image name>_<row number>.<suffix>.
Image MIME will be detected and added to the image attributes.[Config] menu, the [ODT Reports] form is available, with which it is possible to define reports providing the templates used for assembling and defining the portions with the relative data extraction queries for printing.
Two buttons in the form are present: (Test ODT and Test PDF), with which reports are generated and then downloaded in the ODT or PDF formats using the parameters indicated in the Test parameters field.ODT format does not include eventual portions in PDF type (files and attached reports) that are ignored.
The files of templates are attached to the reports table (public.odt_reports) and can be downloaded thusly from the form. Every report have a separate archive of files, eventually organized in subforders.| term | description |
|---|---|
template |
generic document containing the particulars of structure or graphics in which information is entered using references to external data |
print template |
file in the ODT format used as basis for constructing the document |
section |
part of an ODT document countersigned marked with a name |
portion |
portion of report, generated using a section, table, or an ODT document |
report |
ODT formated document |
DTL |
Django Template Language; used to insert data in templates and in queries |
data |
data can be provided from the report generator as parameters (at the command line) or as result from queries |
query |
Instructions in the SQL format to extract data from the database. The query main contain constructs in the DTL format |
| table name | description |
|---|---|
public.odt_reports |
list of reports |
public.odt_report_portions |
list of report portions |
| field name | description |
|---|---|
id |
primary key |
name |
report name |
description |
brief report description |
comment |
comment/long report description |
cmd_parameters |
field used by the configurator to send the parameters to the generator for test prints. The format is like "param1=number param2='my string' " |
| field name | description |
|---|---|
id |
primary key |
ord |
order of processing |
id_odt_report |
referring to the reportÂs primary key |
name |
portion name |
id_father |
primary key of father portion |
type |
portion type |
file_name |
file name of template or of file where in the object used as template is present (also indicate the path where the file was saved in a subfolder or report archive) |
obj_ref |
reference name of object used as template |
query |
SQL query |
public.odt_report_portions table, the portions to be processed will be determined based on the following schema that stabilises the values by attributing the type, file_name, and obj_ref fields:
| type | description of portion | file_name | obj_ref |
|---|---|---|---|
base_report |
document template to be used as basis | ODT file name |
|
odt_section |
ODT section | ODT file name from which the section is copied |
section name |
odt_table |
ODT table |
ODT file name from which the section is copied |
table name |
odt_file |
file in ODT format |
ODT filename |
|
pdf_file |
file in PDF format, to be attached |
PDF file name |
|
pdf_report |
report to be attached, in PDF format |
report name |
file_name and obj_ref fields may contain DTL constructs, so it is possible to make the sources from which to download templates and attachments parametric.
The query of the portion is valued first; then, the file_name and obj_ref fields for each row returned by the query. In such way it will be possible to change the template, row by row.
ODT document template to be used as basis for report generation.DTL constructs, useful for processing the page header and footer but also any other objects of the base document.ODT type portions (odt_section, odt_table and odt_file) because it is used as a container for them.PDF type portions (pdf_file and pdf_report) .ODT documents are included, the styles applied will be those defined in the base document, defined here.
ODT section present in the file, identified with its own name.odt_file field is undefined, the section will be read from the base_report template file.ODT table present in the file, identified with its name.odt_file field is undefined, the section will be read from the base_report template file.ODT file.DTL interpretation will be applied to the content.PDF format and attached.
ODT documents generated with Libreoffice suffer from a bug that causes the proliferation of SPAN elements even if different formatting attributes are not included, compared to the adjacent text.
The problem is documented here:
The following XML code shows the problem, which prevents the parser from interpreting DTL constructs correctly:
<style:style style:name="T5" style:family="text"><style:text-properties officeooo:rsid="00260f63"/></style:style>
. . . .
<text:p text:style-name="P9">{{ <text:span text:style-name="T5">Ordini</text:span>.stato_ordine }}</text:p>
Prior to applying the DTL parser, it is then necessary to verify if there are no text:span elements with style containing only officeooo:rsid properties which will be deleted prior to proceed with the parsing.
demo.employees, demo.orders, and demo.commissions.
If the report is recalled with the ID_EMPLOYEE parameter, a single employee will be printed with that primary key.
Thus, we must define two queries: SELECT
id,
name,
surname,
FROM demo.employees
WHERE {% if not defined ARGV.ID_EMPLOYEE %}true{% endif %} or id = '{{ ARGV.ID_EMPLOYEE }}'::integer;
We will limit the list in case the ARGV.ID_EMPLOYEE would be defined (variable supplied to command line) to a single employee that has the id field equal to the variable.
SELECT
price,
type,
percentage as perc
FROM demo.orders
INNER JOIN demo.commissions ON commissions.id = orders.commission
WHERE orders.employee = {{ EB.id }};
We will limit the list using the EB.id variable that corresponds to the id field (employee's primary key) from the first query; because we will call the report portion corresponding to the first query with the name EB (Employee body).
Assuming that a sample report in the public.odt_reports table has been defined with the following values:
| id | name | description |
comment | cmd_parameters |
|---|---|---|---|---|
| 23 | demoreport | example of report | no comment | ID_EMPLOYEE=3 |
my_templates.odt has been loaded with the templates, the portions table will assume the following values:
| id | ord | id_odt_report | name | id_father | type | file_name | obj_ref | query |
|---|---|---|---|---|---|---|---|---|
| 18 | 1 | 23 | base_report | my_templates.odt | ||||
| 19 | 2 | 23 | odt_section | employees_header{% defined ARGV.ID_EMPLOYEE %}_SINGLE{% endif %} | ||||
| 14 | 3 | 23 | EB | odt_section | employees_body | SELECT id, name, surname, FROM demo.employees WHERE {% if not defined ARGV.ID_EMPLOYEE %}true{% endif %} or id = '{{ ARGV.ID_EMPLOYEE }}'::integer; |
||
| 21 | 4 | 23 | 14 | odt_section | orders_header | |||
| 22 | 5 | 23 | OB | 14 | odt_section | orders_body | SELECT price, type, percentage as perc FROM demo.orders INNER JOIN demo.commissions ON commissions.id = orders.commission WHERE orders.employee = {{ EB.id }}; |
|
| 23 | 6 | 23 | 14 | odt_section | orders_footer | |||
| 24 | 7 | 23 | odt_section | employees_footer |
employees_header section:
=================================================
List orders divided per employee
=================================================
Sezione employees_header_SINGLE:
=================================================
Orders of an employee
=================================================
employees_body section
Employee {{ EB.name }} {{ EB.surname }}
orders_header section
+---------------+--------------+----------------+ | price | % commission | type |
orders_body section
+---------------+--------------+----------------+
| {% sprintf "%13.2f" OB.price %} | {% sprintf "%12.2f" OB.perc %} | {% sprintf "%13s" OB.type %} |
orders_footer section
+---------------+--------------+----------------+
[{% sprintf '%3i' EB.id %}]
employees_footer section
=================================================To obtain a similar report to the following, assuming the generator is called with the
ID_EMPLOYEE=3 parameter:
=================================================
Orders of an employee
=================================================
Employee Ted Danson
+---------------+--------------+----------------+
| price | % commission | type |
+---------------+--------------+----------------+
| 12.50 | 12% | Breads |
+---------------+--------------+----------------+
| 230.00 | 20% | Drinks |
+---------------+--------------+----------------+
| 345.33 | 10% | Prepared |
+---------------+--------------+----------------+
[ 3]
=================================================
Copyright (©) Leader.IT - Italy P.I. IT01434390223 Privacy policy & use of cookies