Report Generation Concepts

GroupDocs.Assembly Cloud is a powerful web-based Document Automation and Report Generation solution, designed to generate data-bound documents through templates dynamically.

The main Report Generation concept, presented on the image below, is simple and consistent:

Report Generation Concepts

Document Templates

A document template is just a normal document, created with Microsoft Office, OpenOffice or any other compatible office suite (LibreOffice, WPS Office, Polaris Office, Open365, SoftMaker FreeOffice, etc.), that contains special tags for the dynamic content. You are supposed to use that template to assemble documents on this model repeatedly and consistently.

Have a note, that supported template types are not limited to word-processing document templates only, but also include spreadsheet templates, presentation templates, HTML document templates, email document templates, plain-text templates and others.

Data Sources

A Data Source lets you define which data set will be used to bind with a document template and subsequently evaluated in the output.

You can use both JSON and XML files for this purpose. Both formats are hierarchical, self-describing and human-readable. However, JSON may have slight built-in advantages, because it is more compact and thus it is quicker to read and write.

You can use the following simple data types in your JSON and XML files:

Data TypeDescriptionXML ExampleJSON Example
Int32A 32-bit signed integer

<Age>30</Age>

{"Age": "30"}

Int64A 64-bit signed integer

<Amount>5612456179438</Amount>

{"Amount": "5612456179438"}

DoubleA double-precision floating-point number

<Price>253.9</Price>

{"Price": "253.9"}

BooleanA boolean value (True or False)

<IsChecked>True</IsChecked>

{"IsChecked": "True"}

DateTimeAn instant in time

<OrderDate>2019-10-01T00:00:00</OrderDate>

{"OrderDate": "2019-10-01T00:00:00"}

StringA sequence of Unicode characters

<Name>John Doe</Name>

{"Name": "John Doe"}

Tags and Expressions

Tags and Expressions are the fundamental elements of the report generation technique, that are located in the document template and intended for the purposes of dynamic content management. At its simplest, a tag defines a command for the Reporting Engine, and the expression, which is an integral part of the tag, defines command’s parameters.

In terms of the Reporting Engine, it does not matter what type of document templates you are working with — regardless of the document template type, tags and expression syntax remains the same anywhere. However, you need to use character escaping when working with HTML templates.

A tag is surrounded with a pair of “<<”, “>>” character sequences and consists of the following elements: name, expression, switches and comment:

<<tagName [expression] -switch1 -switch2 ... //comment>>

Some tags require a corresponding closing tag. A closing tag must match the name of the opening tag with the “/” character preceding its name:

<</tagName>>

Depending on the functional role, the following types of tags can be distinguished:

Tag TypeFunctional RoleTagsTags Description
Control TagsProvides flow and conditional processing controlforeach, nextProvides flow control for traversing elements of a certain type in a sequence
if, else, elseifProvides conditional processing control
Content TagsUsed to generate and insert different content elements into the output dynamicallybackColorDefines a background-color for a text
barcodeInserts a barcode image
checkSets a checkbox value
linkInserts a hyperlink
restartNumRestarts a numbering inside a list
varDeclares a variable
Chart TagsUsed to populate charts with datapointColorDefines a color for a chart series
removeifRemoves a chart series, depending on the condition
seriesColorDefines a color of a chart series
sizeDefines a bubble size for a bubble chart
x, ySpecifies a data mapping for chart coordinates

Expressions are the most interesting part of a tag syntax. They are composed of operands, usually presented in the form of Data Field references, and Operators, defined according to the “C# Language Specification 5.0”.

Data Bands

A Data Band is a template for sequential data processing. During the document generation process, the Reporting Engine connects each data band to a data source using Data Field references and processes it as many times as there are records in the data source. As a result, the data band body is replicated and appended to the output document.

Data Band Syntax

A data band is made up of two parts:

  • A pair of opening and closing foreach loop tags, that represent the scope of a control flow statement for traversing elements in a sequence. Depending upon the developer’s objectives the foreach tag syntax may vary.
  • A Data Band Body, defined between the foreach pair of tags, which represents a template for a single element of a sequence. A data band body may contain nested data bands.

The complete syntax of a data band is provided below:

<<foreach [varType varName in sequence]>>data_band_body<</foreach>>

An iteration variable, defined by name and type, is intended to reference an element of a sequence inside a data band body.

Variable’s name and type are optional parameters, that can be specified or omitted depending on the aspects described in the following table:

ParameterUse Aspects
Variable Type
  • If you specify the variable's type explicitly, it must be known by the Reporting Engine.
  • If you omit the variable's data type, it is determined implicitly depending on the type of the corresponding element sequence.
Variable Name
  • If you specify the variable's name, it must be unique within the scope of the corresponding foreach tag.
  • If you omit the variable's name, you can still access the variable’s members using the Contextual Field Access syntax.

Data Band Types

When a data band is related to a list, it is called a Common Data Band.

When a data band is related to a table, that is to a single or multiple rows of a table, it is called a Table-Row Data Band.

Depending on the objectives, this type of data band may occupy a different number of table rows. In the simplest cases, it occupies a single row, but in more complicated scenarios, that imply generation of hierarchical tabular data structures, using multirow data bands may be required.

Referencing Fields in a Data Source

To reference a field inside a data source you must provide a string representation of it.

A field reference syntax is straightforward:

<<[field_reference]>>

To make this baseline technique clear, let’s have a look at the sample data sources in XML and JSON and the corresponding data band.

The following XML and JSON data sources represent a list of persons, described by their names and ages.

XML DataJSON Data
<Persons>  
  <Person>  
     <Name>John Doe</Name>  
     <Age>30</Age>  
  </Person>  
  <Person>  
     <Name>Jane Doe</Name>  
     <Age>27</Age>  
  </Person>  
  <Person>  
     <Name>John Smith</Name>  
     <Age>51</Age>  
  </Person>  
</Persons>
{"Persons":
  {"Person":
    [  
      { "Name": "John Doe",  
       "Age": "30"  
      },  
      {  
       "Name": "Jane Doe",  
       "Age": "27"  
      },  
      {  
       "Name": "John Smith",  
       "Age": "51"  
      }  
    ]
  }  
}

The corresponding table-row data band is shown below. As you can see, it is referencing the Name and Age fields inside the ds data source, and intended to output the sequence of Person elements to a tabular format in three columns:

NumberNameAge

<<foreach [p in ds.Persons]>><<[p.NumberOf()]>>

<<[p.Name]>>

<<[p.Age]>><</foreach>>

Count

<<[ds.Persons.Count()]>>

When the report generation process is complete, you’ll see the following output:

NumberNameAge
1John Doe30
2Jane Doe27
3John Smith51
Count3

You can also use the Contextual Field Access technique, which enables you to access fields of a data source depending on the processing context. An object, to which the Contextual Field Access can be applied, is determined by the following rules:

  • Inside a data band body, the object is resolved to the iteration variable.
  • Outside a data band body, the object is resolved to a passed data source.

The main syntax differences between the standard and the contextual types of field access are submitted in the following table:

Type of Field AccessIteration Loop SyntaxField Access Syntax
Standard

<<foreach [variable in sequence]>>

<<[variable.Field]>>

Contextual

<<foreach [in sequence]>>

<<[Field]>>

The complete table-row data band example, that demonstates the Contextual Field Access technique, is provided below:

NumberNameAge

<<foreach [in Persons]>><<[NumberOf()]>>

<<[Name]>>

<<[Age]>><</foreach>>

Count

<<[Persons.Count()]>>

Managing Paragraph Breaks

While building a report, paragraph breaks derive attributes from their template prototypes. In particular, this fact enables you to build numbered or bulleted lists in reports dynamically.

The following table illustrates some common use-cases with a “” symbol, that represents a non-printing control character of a paragraph break.

Given an enumeration of strings ["item1", "item2", "item3"] and a common data band in the left column of the following table, you will get the output, shown in the right column:

Data BandOutput
prefix <<foreach [item in items]>><<[item]>>
<</foreach>>suffix
prefix item1¶`
item2
item3
suffix
prefix<<foreach [item in items]>>
<<[item]>><</foreach>> suffix
prefix
item1
item2
item3 suffix
prefix
<<foreach [item in items]>><<[item]>>
<</foreach>>suffix
prefix
item1
item2
item3
suffix
prefix<<foreach [item in items]>>
<<[item]>><</foreach>>
suffix
prefix
item1
item2
item3
suffix

Passing Control to the Next Loop Iteration

You can instruct the Reporting Engine to force movement to the next iteration within a data band using the next tag. This feature is useful in scenarios when you need to output data of a fixed number of elements in a single row.

In the following example, given an enumeration of Person data elements, you can output their names in a row using the following table-row data band:

Name AName BName C

<<foreach [p in Persons]>><<[p.Name]>>

<<next>><<[p.Name]>>

<<next>><<[p.Name]>><</foreach>>

The result would be as follows:

Name AName BName C
John DoeJane DoeJohn Smith

Multi-Row Data Bands

The main purpose of a table-row data band, spread over multiple rows, is to generate nested data structures, for example, in-table lists. The body of this data band starts at the beginning of the first occupied row and ends at the end of the last occupied row as follows:

<<foreach>>

......
...
......

<</foreach>>

The next example demonstrates this advanced technique and shows how to populate a Manager/Client table with a nested in-table Contracts list. Note that the first (outer) data band, that is responsible for iterating and dealing with Manager data elements, occupies two table rows:

Manager / ClientContract Price

<<foreach [m in ds.Managers]>><<[m.Name]>>

<<foreach [m in ds.Managers]>><<[m.Name]>>

<<foreach [m in ds.Managers]>><<[m.Name]>>

<<[c.Price]>><</foreach>><</foreach>>

Count

<<[ds.Contracts.Sum(c => c.Price)]>>

Conditional Data Processing

A Conditional Block represents a set of template options, bound to associated conditional expressions. During the process of Report Generation, these conditional expressions are sequentially evaluated until an expression that returns True is reached. In this case, the conditional block is replaced with the corresponding template option and populated with data.

A conditional block can have a default template <<else>> option that is not bound with a conditional expression. This template option is used when none of the conditional expressions return True.

You can use the following syntax to declare a conditional block:

<<if [condition_1]>>
    template_option_1
<<elseif [condition_2]>>
    template_option_2
           ...
<<elseif [condition_N]>>
    template_option_N
<<else>>
    default_template_option
<</if>>

The following example shows how you can use conditional expressions to represent a number of elements in a sequence, handling the situation when the sequence is empty:

You have chosen <<if [!items.Any()]>>no items<<else>><<[items.Count()]>> item(s)<</if>>.

A template option of a conditional block can be composed of multiple paragraphs and data bands.

For example, given an enumeration of strings ["item1", "item2", "item3"], you can tentatively check whether the enumeration contains any elements before sending them to output:

<<if [!items.Any()]>>No data.<<else>><<foreach [item in items]>><<[item]>><</foreach>><</if>>

Given the previous declaration of string items, you can use the following template to apply different formatting for even and odd elements of the sequence:

<<foreach [item in items]>><<if [IndexOf() % 2 == 1]>><<[item]>><<else>><<[item]>><</if>><</foreach>>

In this case, the engine produces a report as follows:

item1
item2
item3

By analogy with table-row data bands, when a conditional block is related to a table, that is to a single or multiple rows of a table, it is called a Table-Row Conditional Block.

Depending on the objectives, this conditional block may occupy a different number of table rows. In the simplest cases, it occupies a single row, but in many cases it occupies multiple rows of a table.

The body of a table-row conditional block, spread over multiple rows, as well as the body of its every template option, starts at the beginning of the first occupied row and ends at the end of the last occupied row as shown below:

<<if [condition_1]>>

......

<<elseif [condition_2]>>

......

<<elseif [condition_N]>>

......

<<else>>

...

<</if>>

See Also