Skip to end of metadata
Go to start of metadata

This article is the first part of the Template Syntax series of articles. For second part, please visit Template Syntax - Part 2 of 2.

Contents Summary
  

Composing Template

A typical template for GroupDocs.Assembly Engine is composed of common document contents and tags that describe the template's structure and data bindings. You can form these tags using just running text that can occupy multiple paragraphs to be more descriptive.

A tag body must meet the following requirements:

  • A tag body must be surrounded by "<<" and ">>" character sequences.
  • A tag body must contain only text nodes.
  • A tag body must not be located inside markup document nodes.

A tag body typically consists of the following elements:

  • A tag name
  • An expression surrounded by brackets
  • A set of switches available for the tag, each of which is preceded by the "-" character

An optional comment can be written to provide a human-readable explanation.

The optional comment feature is supported by version 19.1 or greater

Particular tags can have additional elements. Some tags require closing counterparts. A closing tag has the "/" character that precedes its name. This tag's name must match to the name of the corresponding opening tag.

Note: Tag body elements are case-sensitive.

Composing Expressions

Using Lexical Tokens

The following table describes lexical tokens that you can use in template expressions and restrictions on these tokens' usage comparing with C# Language Specification 5.0.

Token

Restrictions

Keyword

Only the following tokens are reserved as keywords: true, false, null, new, and in

Identifier

  • The feature of keyword escaping through the "@" character is not supported.
  • Unicode character escapes are not permitted in identifiers.

Literal

None

Operator

See Using Operators

You can use the following identifiers that are not preceded by a member access operator in template expressions:

  • The name of a passed data source object
  • The name of an iteration variable within its scope (see Outputting Sequential Data for more information)
  • The name of a lambda function parameter within the scope of the lambda function
  • A fully or partially qualified name of a type that is known by the engine (see Setting up Known External Types for more information)
  • The name of a member of an object that is determined as follows:
    • Inside a data band body, the object is resolved to the innermost iteration variable.
    • Outside a data band body, the object is resolved to a passed data source.

The feature of the omitting of an object identifier while accessing the object's members is also known as the contextual object member access. See Using Contextual Object Member Access for more information.

Using Types

GroupDocs.Assembly Engine enables you to use external visible types in template expressions. A visible type is a public type with outer types (if any) are public as well. You can use a data source object of any visible type to pass it to the engine.

However, you can use the identifier of a visible type in template expressions only if the following additional requirements are met:

  • The type is not void.
  • The type does not represent an array.
  • The type is not an open or closed generic type.

Note: Whereas using of generic types' identifiers is forbidden in template expressions, you can use identifiers of nullable types in the shorthand "T?" form.

Also, the engine enables you to use anonymous types in template expressions. Such types are useful while composing expressions with grouping by multiple keys. See Enumeration Extension Methods for the examples.

Type Members

GroupDocs.Assembly Engine enables you to access the following public (static and instance) members of accessible types in template expressions:

  • Fields
  • Properties
  • Indexer getters
  • Methods
  • Constructors

However, you can use a functional type member in template expressions only if the following additional requirements are met:

  • The functional member returns a value.
  • The functional member does not have ref or out parameters.
  • The functional member does not take generic type arguments.

The engine supports the following features when dealing with functional members:

  • Overload resolution according to C# Language Specification 5.0
  • Using of default parameter values without support of named parameters
  • Using of parameters taking a variable number of arguments

Using Extension Methods

GroupDocs.Assembly Engine enables you to use the following built-in extension methods in template expressions:

Note: Extension methods, other than the built-in ones, can be used only in the form of plain static methods in template expressions.

Using Operators

The following list contains predefined and user-defined operators that Document Assembler enables you to use in template expressions.

  • Primary:

  • Unary:

  • Binary:

  • Ternary:

The engine follows operator precedence, associativity and overload resolution rules declared at C# Language Specification 5.0 while evaluating template expressions. But be aware of the following limitations in the behavior comparing with the specification:

  • Implicit user-defined conversions are supported only when specified explicitly.
  • The indexing of multi-dimensional arrays is not supported.
  • Whereas the object initializer syntax is supported (including objects of anonymous types), the collection initializer syntax is not.

Also, the engine enables you to use lifted operators in template expressions.

Using Lambda Functions

GroupDocs.Assembly Engine enables you to use lambda functions only as arguments of built-in enumeration extension methods in template expressions. See Enumeration Extension Methods for more information.

Note: Lambda functions declared within template expressions are not interchangeable with delegates. Thus, you can not pass delegates as arguments to built-in enumeration extension methods.

You can use both explicit and implicit lambda function signatures in template expressions. If you do not specify the type of a parameter of a lambda function explicitly, the type is determined implicitly by the engine depending on the type of the corresponding enumeration.

Using Data Sources

DataSet Objects

This link will explain you how we utilized the DataSet Objects in Business Layer.

GroupDocs.Assembly Engine enables you to access DataTable objects contained within a particular DataSet instance by table names using the "." operator in template expressions. That is, for example, given that ds is a DataSet instance that contains a DataTable named "Persons", you can access the table using the following syntax.

Note Table names are case-insensitive.

DataTable and DataView Objects

GroupDocs.Assembly Engine enables you to treat DataTable and DataView objects in template expressions as enumerations of their rows. That is, you can use template expressions evaluated to such objects in foreach tags (see Outputting Sequential Data for more information).

Also, you can normally apply enumeration extension methods (see Enumeration Extension Methods for more information) to DataTable and DataView objects in template expressions. For example, given that persons is a DataTable or DataView instance, you can count its rows using the following syntax.

DataRow and DataRowView Objects

GroupDocs.Assembly Engine enables you to access a data associated with a particular DataRow or DataRowView instance in template expressions using the "." operator. The following table describes, which identifiers you can use to access different kinds of the data.

Data Kind

Identifier

Examples of Template Expressions

Field Value

Field name

Given that r is a row that has a field named "Name", you can access the field's value using the following syntax.

Parent Row

Parent table name

Given that r is a row of a DataTable that has a parent DataTable named "City", you can access the parent row of r using the following syntax.

Given that the "City" DataTable has a field named "Name", you can access the field's value for the parent row using the following syntax.

Child Rows

Child table name

Given that r is a row of a DataTable that has a child DataTable named "Persons", you can access the enumeration of the child rows of r using the following syntax.

Given that the "Persons" DataTable has a field named "Age", you can count the child rows that correspond to persons over thirty years old using the following syntax.

Note: Field and table names are case-insensitive.

To determine parent-child relationships for a particular DataTable instance, the engine uses DataRelation objects contained within the corresponding DataSet instance. Thus, you can manage these relationships in a common way.

IDataReader Implementors

GroupDocs.Assembly Engine enables you to treat IDataReader implementors as enumerations of IDataRecord implementors in template expressions. That is, you can use IDataReader implementors in template expressions in the same way as DataTable objects. See Working with DataTable and DataView Objects for more information.

However, you can not use IDataReader implementors in template expressions in conjunction with enumeration operations that require a caching of enumeration items. The examples of such operations are grouping and sorting. To work around this restriction, use DataTable objects instead.

IDataRecord Implementors

See In-Table Master-Detail template using IDataRecord Implementors.

Document Assembler enables you to access field values of a particular IDataRecord implementor by field names using the "." operator in template expressions. To use this feature, one of the following conditions must be met:

  • The IDataRecord implementor represents an iteration variable upon enumerating an IDataReader implementor (see Outputting Sequential Data for more information).
  • The IDataRecord implementor does not implement the IDataReader interface.

The following example shows, how to use this feature. Given that r is an IDataRecord implementor that has a field named "Name", you can access the field's value using the following syntax.

Note Field names are case-insensitive.

Using Images

See Common List with Image template using images in it.

You can insert images to your reports dynamically using image tags. To declare a dynamically inserted image within your template, please follow these steps:

  1. Add a textbox to your template at the place where you want an image to be inserted.
  2. Set common image attributes such as frame, size, and others for the textbox, making the textbox look like a blank inserted image.
  3. Specify an image tag within the textbox using the following syntax.

The expression declared within an image tag is used by the engine to build an image to be inserted. The expression must return a value of one of the following types:

  • A byte array containing an image data
  • A Stream instance able to read an image data
  • An Image object
  • A string containing an image URI

While building a report, the following procedure is applied to an image tag:

  • The expression declared within the tag is evaluated and its result is used to form an image.
  • The corresponding textbox is filled with this image.
  • The tag is removed from the textbox.

Note: If the expression declared within an image tag returns a stream object, then it is closed by the engine as soon as the corresponding image is built.

By default, the engine stretches an image filling a textbox to the size of the textbox. However, you can change this behavior in the following ways:

  • To keep the width of the textbox and change its height preserving the ratio of the image, use the fitHeight switch as follows:

  • To keep the height of the textbox and change its width preserving the ratio of the image, use the fitWidth switch as follows:

  • To change the size of the textbox according to the size of the image, use the fitSize switch as follows:

Using Contextual Object Member Access

See In-Table List with Filtering, Grouping, and Ordering template Contextual Object Member Access in it.

You can make your templates less cumbersome using the contextual object member access feature. This feature enables you to access members of some objects without specifying the objects' identifiers in template expressions. An object to which the feature can be applied is determined depending on a context as follows:

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

Obviously, inside a data band body, you can not use the feature to access members of an outer iteration variable or a passed data source object. With the exception of this restriction, you can use both contextual and common object member access syntaxes interchangeably depending on your needs and preferences.

Consider the following example. Given that ds is a DataSet instance containing a DataTable object named "Persons" that has fields named "Name" and "Age", you can use the following template to list the contents of the table.

No.

Name

Age

 

 

Alternatively, you can use the following template involving the contextual object member access syntax to get the same results.

No.

Name

Age

 

 

Using Conditional Blocks

You can use different document blocks to represent the same data depending on a condition with the help of conditional blocks. A conditional block represents a set of template options, each of which is bound with a conditional expression. At runtime, these conditional expressions are sequentially evaluated, until an expression that returns true is reached. Then, the conditional block is replaced with the corresponding template option populated with data.
A conditional block can have a default template option that is not bound with a conditional expression. At runtime, this template option is used, when none of conditional expressions return true. If a default template option is missing and none of conditional expressions return true, then the whole conditional block is removed during runtime.

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

Note: A conditional expression must return a Boolean value.

Common Conditional Blocks

See Multicolored Numbered List template using Common Conditional Blocks in it.

A common conditional block is a conditional block which body starts and ends within paragraphs that belong to a single story or table cell.
If a conditional block belongs to a single paragraph, it can be used as a replacement for an expression tag that involves the ternary "?:" operator. For example, given that items is an enumeration, you can use the following template to represent the count of elements in the enumeration:

Note: A template option of a common conditional block can be composed of multiple paragraphs, if needed.

You can normally use common conditional blocks within data bands. For example, given that items is an enumeration of the strings "item1", "item2", and "item3", you can use the following template to enumerate them and apply different formatting for even and odd elements:

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

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

item1
item2
item3

You can use data bands within common conditional blocks as well. For example, given the previous declaration of items, you can check whether the enumeration contains any elements before outputting their list:

Table-Row Conditional Block

See In-Table List with Highlighted Rows template using Table-Row Conditional Block.

A table-row conditional block is a conditional block which body occupies single or multiple rows of a single document table. The body of such a block (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 follows:
Note: Table rows occupied by different template options in the following template are highlighted with different colors.

 

 

 

<<if ...>> ...

...

...

...

...

...

<<elseif ...>> ...

...

...

...

...

...

<<else>> ...

...

...

...

...

...

...

...

... <</if>>

 

 

 

The following examples in this section are given using client, an instance of the Client class, and clients, an enumeration of instances of the Client class that is defined as follows:

Using table-row conditional blocks, you can pick to output a single row among several rows of a single document table depending on a condition like in the following example:

...

...

...

<<if [client.Country == "New Zealand"]>><<[client.Name]>>

<<[client.LocalAddress]>>

<<else>><<[client.Name]>>

<<[client.Country]>>

<<[client.LocalAddress]>><</if>>

...

...

...

You can normally use table-row conditional blocks within data bands to make elements of an enumeration look differently depending on a condition. Consider the following template:

<<foreach [in clients]>><<if [Country == "New Zealand"]>><<[Name]>>

<<[LocalAddress]>>

<<else>><<[Name]>>

<<[Country]>>

<<[LocalAddress]>><</if>><</foreach>>

In this case, the engine produces the report as below:

A Company

Australia

219-241 Cleveland St

STRAWBERRY HILLS  NSW  1427

B Ltd.

Brazil

Avenida João Jorge, 112, ap. 31

Vila Industrial

Campinas - SP

13035-680

C & D

Canada

101-3485 RUE DE LA MONTAGNE

MONTRÉAL (QUÉBEC) h2G 2A6

E Corp.

445 Mount Eden Road

Mount Eden

Auckland 1024

F & Partners

20 Greens Road

Tuahiwi

Kaiapoi 7691

G & Co.

Greece

Karkisias 6

GR-111 42  ATHINA

GRÉCE

H Group

Hungary

Budapest

Fiktív utca 82., IV. em./28.

2806

I & Sons

43 Vogel Street

Roslyn

Palmerston North 4414

J Ent.

Japan

Hakusan 4-Ch?me 3-2

Bunky?-ku, T?KY?

112-0001

Japan

Note: You can use common conditional blocks within table-row data bands as well.

Also, you can use data bands inside table-row conditional blocks. For example, you can provide an alternate content for an empty table-row data band using the following template:

Client

Country

Local Address

<<if [!clients.Any()]>>No data

<<else>><<foreach [in clients]>><<[Name]>>

<<[Country]>>

<<[LocalAddress]>><</foreach>><</if>>

In case, the corresponding enumeration is empty, the engine produces a report as below:

Client

Country

Local Address

No data

Note: If tags denoting boundaries of a template option are contained within a single table cell, the option is considered to be a common template option, rather than a table-row one. That is, the option is considered to occupy contents within the cell, rather than the whole row. That is why, a single-cell alternate content in the previous example is located between an opening if and else tags, rather than between an else and closing if tags.

Labels
  • No labels