Storing and Retrieving Variables
Storing Variables for Later Use
Store the output of macros for use in later macros using the storeAs (or storeAsHidden) parameter. Please note:
- Variable names may contain only the following characters: AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz_0123456789
- Variable names must not start with any of: 0123456789
The value and type are stored, for example, if you store 1234 as a 32-bit integer in variable "X", X will be treated as a 32-bit integer until either:
- The end of the report, or
- You overwrite it with a value of a different type
When storing complex data structures, best practice is to avoid strings and use lists instead. Older report templates may store table-like data as a string, which can fail if a special character such as one of [, ; ^ " ` or =] is present in a cell.
Example of older string-based storage:
[String: value=Col1^Col2^Col3;{Row1Col1Value}^{Row1Col2Value}^{Row1Col3Value};{Row2Col1Value}^{Row2Col2Value}^{Row2Col3Value}]
Preferred approach (list-based):
[Calculate: value=`list(list('Col1', 'Col2', 'Col3'), list(Row1Col1Value, Row1Col2Value, Row1Col3Value), list(Row2Col1Value, Row2Col2Value, Row2Col3Value))`]
Examples of Stored Variables
| Macro | Variable name | Value type | Value | String inserted into report | Notes |
|---|---|---|---|---|---|
| [String: value=Amanda, storeAs=FirstName] | FirstName | String | Amanda | Amanda | FirstName is a string and will be visible in the output document. |
| [String: value=Jones, storeAsHidden=LastName] | LastName | String | Jones | LastName is a string and will not be visible in the output document because the variable was stored using storeAsHidden instead of storeAs. | |
| [:Rachael,=>MiddleName] | MiddleName | String | Rachael | The shorthand form of the String macro is used. MiddleName is a string and will not be visible in the output document because the shorthand form stores with storeAsHidden behaviour. | |
| [String: value="BA, MSc", storeAsHidden=Qualifications] | Qualifications | String | BA, MSc | Qualifications is a string. Because the value contains a comma, it is enclosed in double quotes. You can also use a backtick character (`), for example when storing a value that contains double quotes. | |
| [String: value=`Plum Tree Cottage`, storeAsHidden=HouseName] | HouseName | String | Plum Tree Cottage | HouseName is a string. | |
| [String: value=`1234`, storeAsHidden=HouseNumber] | HouseNumber | String | 1234 | HouseNumber is a string, even though it might look like an integer. If you intend an integer, use the [Calculate:] macro. | |
| [Calculate: value=`5678`, storeAsHidden=Steps] | Steps | Int32 | 5678 | Steps is a 32-bit integer (Int32). The type is determined at runtime when the [Calculate:] macro is evaluated. | |
| [=:17,=>Age1] | Age1 | Int32 | 17 | The shorthand form of the Calculate macro is used. Because [Calculate:] evaluates to a 32-bit integer here, the output type is Int32. | |
| [=:17.0,=>Age2] | Age2 | Double | 17 | Because [Calculate:] evaluates to a double-precision floating point number, the output type is Double. | |
| [Calculate: value='448432899811', storeAsHidden=PhoneNumber] | PhoneNumber | String | 448432899811 | PhoneNumber is a string. The type is determined at runtime when [Calculate:] is evaluated. | |
| [Calculate: value=`if(customerIsUk, '08432 899 811', '+44 8432 899 811')`, storeAsHidden=FormattedPhoneNumber] | FormattedPhoneNumber | String | "08432 899 811" or "+44 8432 899 811" | FormattedPhoneNumber is a string. The output depends on whether the customer is in the UK, but both outcomes are strings. | |
| [Calculate: value=`if(IdOutputType == 'text', '1234', 1234)`, storeAsHidden=Id] | Id | String or Int32 | 1234 | The output type depends on whether IdOutputType is set to the string 'text'. | |
| [Calculate: value=`list('a', 123, null)`, storeAsHidden=Things] | Things | List<object?> (list of nullable objects) | [] { "a", 123, null } | When ReportMagic produces lists, they are (in C# / .NET terms) lists of nullable objects. Objects in the list can be any supported type. | |
| [DateTime: format=yyyy-MM-01, storeAsHidden=RightNow, storeFormattedValueAs=FirstOfThisMonth] | RightNow | DateTimeOffset | 2022-02-10T12:34:56Z | 2022-02-01 | This assumes the macro was run at 12:34:56 on 10 February 2022 UTC. ReportMagic always uses UTC. The formatted output is stored in FirstOfThisMonth as a string. |
Retrieving data from variables
There are different ways to retrieve data from variables:
- As part of an NCalc evaluation
- Using Early Evaluation
- Using Late Evaluation
Retrieving data as part of an NCalc evaluation
ReportMagic supports all core NCalc functions, plus those provided by the PanoramicData.NCalcExtensions library. Many macros support evaluation using the NCalc functional language. Key examples are:
- [Calculate: value=`<NCALC OBJECT EXPRESSION GOES HERE>`, storeAsHidden=X]
- [If: condition=`<NCALC BOOLEAN EXPRESSION GOES HERE>`]
NCalc expressions return a value of a specific type. For macros that use the condition parameter (such as [If:]), the result must be a boolean type (true or false). The [Calculate:] macro can return any supported type, including:
- String
- Int32
- Double (64-bit double-precision floating point)
- List<object?> (list of nullable objects)
NCalc evaluation should be used whenever possible, for example with [Calculate:], because:
- Evaluation remains strongly typed, reducing type errors
- You avoid parsing issues caused by special characters such as [, ; ^ " ` =].
- The shorthand [=:] form uses fewer characters, which is useful in table templating
The following two macros are interpreted identically:
[Calculate: value=A+B]
[=:A+B]
Avoid using Early Evaluation inside NCalc expressions. It is unnecessary, harder to read, and more error-prone. For example, if A contains a single comma character:
[Calculate: value=A+B]
...works as expected, whereas:
[Calculate: value={A}+{B}, comment="Don't do this!"]
...does not.
Retrieving data using early evaluation
To use "early evaluation", place curly braces around the variable name. This modifies macro text before it is interpreted. Early evaluation should generally be avoided, but it can be useful:
- When debugging macros
- When constructing a macro as a string
Examples
A simple example:
From the desk of: [String: value={FirstName}][Calculate: value='{Surname}'] Please see your report attached.
Best Wishes, [:{FirstName} {Surname}]
As ReportMagic reads each macro, it replaces curly-brace tokens early, before macro evaluation, so the template is effectively read as:
From the desk of: [String: value=Amanda][Calculate: value='Jones'] Please see your report attached. Best Wishes, [String: value=Amanda Jones]
Example of constructing a macro as a string:
[String: value=`format=N5`, storeAsHidden=Format][Calculate: value=Sqrt(2), {Format}]
ReportMagic reads this as:
[String: value=`format=N5`, storeAsHidden=Format][Calculate: value=Sqrt(2), format=N5]
Pre-/post-increment and decrement
With early evaluation, you can also use pre-/post-increment and decrement as in most C-like languages:
[String: value=0, storeAs=A] A is now 0
[String: value={++A}, storeAs=B] A is now 1, B is now 1
[String: value={A++}, storeAs=C] A is now 2, C is now 1
[String: value={A--}, storeAs=D] A is now 1, D is now 2
[String: value={--A}, storeAs=E] A is now 0, E is now 0
Retrieving Data using late evaluation
When a macro parameter should be set simply to the value in a variable name, use "late evaluation". This means the parameter is populated during the final stages of macro processing, preventing "stray" characters (like commas or spaces) from breaking the macro's logic or being misinterpreted.
For example, the following is not processed correctly:
[String: value=`A, B and C`, storeAsHidden=X][String: value={X}]
...because the final macro is interpreted as value=A, with ReportMagic unable to interpret B and C:
[String: value=A, B and C, storeAsHidden=X]
Using late evaluation you add an equals sign {=X}, which means ReportMagic waits until the very last moment to inject the data.
[String: value=A, B and C, storeAsHidden=X] [String: value={=X}]
This ensures the entire string "A, B and C" is treated as a single value within the parameter.
With Late Evaluation, you can use any NCalc formula:
[:AB, =>X][:CD, =>Y][String: value={=X + Y}]
...produces:
ABCD
Example 2:
[=:10, =>P] [ForEach: values=`{=list(P * 2, P * 4, P * 6)}`, =>Q] [=:Q] [EndForEach:]
...produces:
20 40 60
Enclosing Characters
For most macros, values do not need quotes. However, if a parameter value contains commas, ReportMagic interprets commas as parameter separators. To prevent this, protect the value with double quotes (") or a backtick (`):
[String: value="a, b and c", storeAs=A] [String: value=`a, b and c`, storeAs=A] [String: value=`"a, b and c"`, storeAs=A]
He said [String: value=`{A}`]
Tip: Avoid early evaluation when using values that may contain both double quotes and backticks as they cannot always be safely protected.
Output Formatting and Precision
When working with numbers, ReportMagic maintains full (64-bit) precision where appropriate to avoid later rounding errors.However, when numbers (and other types) are output in the report, the format can be set using C# formatting. For example:
The square root of 2 is [Calculate: value=`Sqrt(2)`, storeAs=A] to 2 decimal places. If you square it, you get back to [Calculate: value=`Pow(A, 2)`]
In Report Studio, the Variables pane shows A stored as 1.4142135623730951, while report output may show 1.41. To display higher precision in output:
The square root of 2 is [Calculate: value=`Sqrt(2)`, storeAs=A, format=N5] to 5 decimal places. If you square it, you get back to [Calculate: value=`Pow(A, 2)`]
To keep lower precision in the variable itself, use Round in [Calculate:]:
[Calculate: value=`Round(A, 2)`]
Viewing Variables
View variables in Report Studio on either of these tabs:
The ALL VARIABLES tab shows all variables created in a report. If multiple macros write to the same variable name, the tab shows only the latest value.
When you click a specific macro block the MACRO VARIABLES tab shows only the variables created by that macro, so you can see the history of that variable at different times in the report, which helps with debugging issues.
To test this, copy these macros into Report Studio:
[String:value=1, storeAs=MyVariable] [String:value=2, storeAs=MyVariable] [String:value=3, storeAs=MyVariable]
The ALL VARIABLES tab shows the one variable (MyVariable) with value 3. If you click the second macro block, you'll see on the MACRO VARIABLES tab that MyVariable is 2.
You cannot enclose numbers in curly brackets or leave stray curly brackets in an expression. For example, the following are not allowed:
- x>{3}
- x>3}
You can use these resources when updating NCalc expressions: