This section describes special techniques, designed to apply data filtering, sorting, grouping and formatting throughout the Report Generation process. There are a number of flexible approaches to data processing depending on what you want to do.
The Reporting Engine supplies a consistent LINQ-based model for working with data, which specifies what elements to retrieve from the data source and, optionally, how that data elements should be filtered, sorted and grouped before exporting to the resulting document.
In practical terms this implies the possibility to use a source element sequence as input and change it in different ways to make an output sequence in a final document. This technique is based on Enumeration Extension Methods, many of which take lambda-functions as arguments.
Using Variables
In the course of data processing, you can define custom variables and use them in expressions. This technique can be useful when you need to calculate expensive expression values just once and apply them several times without the need for recalculation.
You can declare a variable in a document template using a var tag as follows:
<<var[variableTypevariableName=variableValue]>>
After a variable is declared in a template, its value can be accessed using the name of the variable. For example, the following template expression outputs the string “Hello World!”:
Please pay attention, that you can redefine the value of a variable using a var tag, but you can not redefine the type of it.
Using Extension Methods
The Reporting Engine enables you to use the following built-in extension methods in template expressions:
Extension methods of iteration variables.
Extension methods of enumerations.
Now let’s review them in details.
Now let’s review them in details.
Using Extension Methods of Iteration Variables
The Reporting Engine provides two special extension methods of iteration variables: IndexOf() and NumberOf(). They are both created to obtain an index of a sequence element, processed and referred by the iteration variable at the moment, but have a small difference.
The IndexOf() extension method returns a zero-based index (0, 1, 2 …) of a sequence element that is represented by the corresponding iteration variable. You can use this extension method to distinguish sequence items with different indexes and then handle them in different ways.
For example, given that items is an enumeration of the strings ["item1", "item2", "item3"], you can use the following template to prefix all of them with commas except the first one:
In this case, the Reporting Engine produces the following output:
Theitemsare:item1,item2,item3.
By analogy with the previous case, the NumberOf() extension method returns a one-based index (1, 2, 3 …) of a sequence element.
For example, given the previous declaration of items, you can enumerate and number them in a table, starting naturally with number 1, with the following template:
Number
Item
<<foreach [item in items]>><<[item.NumberOf()]>>
<<[item]>><</foreach>>
The resulting output would be as follows:
Number
Item
1
item1
2
item2
3
item3
Using Enumeration Extension Methods
The Reporting Engine enables you to perform common manipulations on a sequential data through the engine’s built-in extension methods. These extension methods emulate some extension methods of .NET Framework IEnumerable interface, providing the same signatures and behavior features.
Thus, you can group, sort, and perform other sequential data manipulations in template expressions in a familiar way.
The following table describes the built-in extension methods. Several notation conventions are used within the table:
Selector stands for a lambda function returning a value and taking an enumeration item as its single argument.
ComparableSelector stands for the Selector returning IComparable interface.
Predicate stands for the Selector returning a boolean value.
Extension Method
Argument
Description
Examples and Notes
All
(Predicate)
Determines whether all elements of a sequence satisfy a condition
persons.All(p => p.Age < 50)
Any
()
Determines whether a sequence contains any elements
persons.Any()
(Predicate)
Determines whether any element of a sequence satisfies a condition
persons.Any(p => p.Name == "John Smith")
Average
(Selector)
Computes the average of a sequence of numeric values
persons.Average(p => p.Age)
The input selector must return a value of any type that has predefined or user-defined addition and division operators.
Concat
(IEnumerable)
Concatenates two sequences
persons.Concat(otherPersons)
An implicit reference conversion must exist between types of items of concatenated enumerations.
Contains
(Object)
Determines whether a sequence contains a specified element
persons.Contains(otherPersons.First())
Count
()
Returns the number of elements in a sequence
persons.Count()
(Predicate)
Returns a number that represents how many elements in the specified sequence satisfy a condition
persons.Count(p => p.Age > 30)
Distinct
()
Returns distinct elements from a sequence
persons.Distinct()
First
()
Returns the first element of a sequence
persons.First()
(Predicate)
Returns the first element in a sequence that satisfies a specified condition
persons.First(p => p.Age > 30)
FirstOrDefault
()
Returns the first element of a sequence, or a default value if the sequence contains no elements
persons.FirstOrDefault()
(Predicate)
Returns the first element of the sequence that satisfies a condition or a default value if no such element is found
persons.FirstOrDefault(p => p.Age > 30)
GroupBy
(Selector)
Groups the elements of a sequence according to a specified key selector function and creates a result value from each group and its key
persons.GroupBy(p => p.Age)
or
persons.GroupBy(p => new { Age = p.Age, Count = p.Children.Count() })
This method returns an enumeration of group objects. Each group has a unique key defined by the input selector and contains items of the source enumeration associated with this key. You can access the key of a group instance using the Key property. You can treat a group itself as an enumeration of items that the group contains.
Last
()
Returns the last element of a sequence
persons.Last()
(Predicate)
Returns the last element of a sequence that satisfies a specified condition
persons.Last(p => p.Age > 100)
LastOrDefault
()
Returns the last element of a sequence, or a default value if the sequence contains no elements
persons.LastOrDefault()
(Predicate)
Returns the last element of a sequence that satisfies a condition or a default value if no such element is found
persons.LastOrDefault(p => p.Age > 100)
Max
(ComparableSelector)
Returns the maximum value in a sequence of values
persons.Max(p => p.Age)
Min
(ComparableSelector)
Returns the minimum value in a sequence of values
persons.Min(p => p.Age)
OrderBy
(ComparableSelector)
Sorts the elements of a sequence in ascending order
This method returns an enumeration ordered by a single key. To specify additional ordering keys, you can use the following extension methods of an ordered enumeration:
ThenBy(ComparableSelector)
ThenByDescending(ComparableSelector)
OrderByDescending
(ComparableSelector)
Sorts the elements of a sequence in descending order
Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence
persons.Single()
(Predicate)
Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists
persons.Single(p => p.Name == "John Smith")
SingleOrDefault
()
Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence
persons.SingleOrDefault()
(Predicate)
Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists; this method throws an exception if more than one element satisfies the condition
Bypasses a specified number of elements in a sequence and then returns the remaining elements
persons.Skip(10)
SkipWhile
(Predicate)
Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements
persons.SkipWhile(p => p.Age < 21)
Sum
(Selector)
Computes the sum of a sequence of numeric values
persons.Sum(p => p.Children.Count())
The input selector must return a value of any type that has a predefined or user-defined addition operator.
Take
(int)
Returns a specified number of contiguous elements from the start of a sequence.
persons.Take(5)
TakeWhile
(Predicate)
Returns elements from a sequence as long as a specified condition is true
persons.TakeWhile(p => p.Age < 50)
Union
(IEnumerable)
Produces the set union of two sequences
persons.Union(otherPersons)
An implicit reference conversion must exist between types of items of united enumerations.
Where
(Predicate)
Filters a sequence of values based on a predicate
persons.Where(p => p.Age > 18)
Data Formatting
Formatting is the process of converting an instance of a class (numeric, string, date-time) to its string representation. You can output expression results to your reports using expression tags, which has no special name and consists of the following elements:
An expression enclosed by square brackets.
An optional format string enclosed by double quotes and preceded by the “:” character.
An optional -html switch.
The complete syntax of a formatting expression is shown below:
<<[expression]:"format"-html>>
If -html switch is present, the expression result is considered to be an HTML block. For example, the following tag is replaced with content like “Bold and italic text” at runtime.
<<["<b>Bold</b> and <i>italic</i> text"]-html>>
Formatting Numeric and DateTime Expressions
To format a numeric or date-time expression result, you can specify a format string as an element of the corresponding expression tag. You can get the detailed information on the possibilities of the base-type formatting in the article “Format types in .NET”, submitted by Microsoft.
For example, given that d is a DateTime value, you can use the following template to format values using the "yyyy.MM.dd" pattern:
<<[d]:"yyyy.MM.dd">>
Additional Number Formats
Several additional number formats, that are missing in standard .NET libraries, are supported:
Number Format
Description
Example
alphabetic
Formats an integer number as an upper-case letter
A, B, C
roman
Formats an integer number as an upper-case Roman numeral
I, II, III
ordinal
Appends an ordinal suffix to an integer number
1st, 2nd, 3rd
ordinalText
Converts an integer number to its ordinal text representation
First, Second, Third
cardinal
Converts an integer number to its text representation
One, Two, Three
hex
Formats an integer number as hexadecimal
8, 9, A, B, C, D, E, F, 10, 11
arabicDash
Encloses an integer number with dashes
- 1 -, - 2 -, - 3 -
You can specify one of these additional number formats instead of a format string like in the following example. Given that i is an integer number, you can format the number as an upper-case letter using the following template:
<<[i]:alphabetic>>
Additional String Formats
Several additional string formats, that are missing in standard .NET libraries, are supported:
String Format
Description
Example
lower
Converts a string to lower case
the string
upper
Converts a string to upper case
THE STRING
caps
Capitalizes a first letter of every word in a string
The String
firstCap
Capitalizes the first letter of the first word in a string
The string
You can specify one of these additional string formats instead of a format string like in the following example. Given that s is a string, you can capitalize the first letter of every word in the string using the following template.
<<[s]:caps>>
Formatting Options Combinations
You can also specify one of the additional string formats together with a format string or an additional number format like in the following examples. Given that d is a DateTime value, you can convert its textual month representation to upper case using the following template:
<<[d]:"MMMM":upper>>
Given that i is an integer number, you can convert the number to a lower-case Roman numeral using the following template:
<<[i]:roman:lower>>
In contrast to format strings, additional numbers and string formats must not be enclosed with double-quotes.
See Also
Format types in .NET, which describes .NET formatting templates and parameters, also supported by the Reporting Engine.
Was this page helpful?
Any additional feedback you'd like to share with us?
Please tell us how we can improve this page.
Thank you for your feedback!
We value your opinion. Your feedback will help us improve our documentation.