In this document, we will introduce various string manipulation, numeric processing, and date/time processing techniques that utilize EL expressions in Questetra. We will also introduce numerous samples of partial and conditional extraction from single-line/multi-line strings, data conversion and information acquisition, as well as formatting and calculation of numbers and dates.
For information on how to write basic EL expressions, please refer to R2272: Auto-Population of Title/String-type Fields (Data Configuration Expressions) and for detailed SpEL specifications, please refer to the SpEL Reference .
*Usage Scenarios
- String transformation in [Update Data]
- Dynamic generation of email body using [Throwing Message Intermediate Event (email)]
*Operation Category
- 1. Operators for Expressions
- 2. String Manipulation (Single line / Multiple line)
- 3. Numeric Formatting and Operations
- 4. Formatting and Comparing Date/Time Data
1. Operators for Expressions
Here is a brief introduction to the operators that are commonly used to write advanced operations in SpEL expressions. For more information, please see the SpEL Operators Reference.
1.1 Logical Operators
By using && (AND) or || (OR), you can combine multiple conditions.
Example: contains("error") && length() >= 8
1.2 Relational Operators
The relational operators include <= (less than or equal to), == (equal), >= (greater than or equal to), != (not equal), and so on.
Examples: #q_string1 == #q_string2 or #q_string1 != #q_string2
1.3 Safe Navigation Operator
The safe navigation operator ?. is used to avoid a NullPointerException. Typically, when you have a reference to an object, you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator returns null for the particular null-safe operation instead of throwing an exception. It applies not only to String-types but also to Numeric or Date/Datetime types.
Sample Expression
#{#q_stringExample?.toUpperCase()}Input Example 1
hello
Output Example 1
HELLO
Input Example 2
Output Example 2
No error occurs if the field is left blank.
1.4 Selection and Projection
In SpEL, operations such as selection ?.? and projection ?.! can be applied to collections like lists.
Selection creates a new collection by extracting only elements that meet certain conditions, whereas projection transforms each element in the collection into a new form.
{1, 2, 3, 4}?.?[#this % 2 == 0] // Selection = {2, 4}
{1, 2, 3, 4}?.![#this * 2] // Projection = {2, 4, 6, 8}
In the above examples, #this refers to each individual element within the list created by {...}. Additionally, there are special selection operations: ?.^[condition] extracts only the first element that satisfies the condition, while ?.$[condition] extracts only the last element that satisfies the condition.
{3, 5, 8, 6, 10}?.^[#this > 5] // = {8} (Select the first element > 5)
{3, 5, 8, 6, 10}?.$[#this > 5] // = {10} (Select the last element > 5)
1.5 Ternary Operator
You can use the ternary operator ? : for performing if-then-else conditional logic inside the expression.
Sample Expression
#{#q_numExample > 100 ? "large" : "small or equal"}Input Example 1
120
Output Example 1
large
Input Example 2
100
Output Example 2
small or equal
2. String Manipulation (Single line / Multiple line)
This section introduces EL expressions for both single-line and multi-line string data. For String-type (multiple lines) data, each line is broken down into list elements (separated by newline characters), the operation is performed on each line, and then the data is rejoined by inserting newline characters.
2.1 Extract substring of a string data
Extract substring after the specified character
In String-type (single line) data, finds the specified character (in this sample, apple), and extracts the substring after the first occurrence of that character. This is useful when you need to remove unnecessary beginning parts of your string data.
Sample Expression
#{#q_stringExample?.substring(#q_stringExample?.indexOf("apple"))}Input Example
banana,apple,orange,apple,grape
Output Example
apple,orange,apple,grape
Extract substring up to the specified character
In String-type (single line) data, finds the specified character (in this sample, "comma"), and extracts the substring up to the last occurrence of that character. This is useful when you need to remove unnecessary parts from the end of your string data.
Sample Expression
#{#q_stringExample?.substring(0, #q_stringExample?.lastIndexOf(","))}Input Example
apple,orange,banana
Output Example
apple,orange
Extract substring with a certain length
For String-type (multiple lines) data, splits each line, extracts a specific number of characters from the beginning of each line, and then rejoins them with newline characters.
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.![substring(0,7)], #NL)}Input Example
123456777 234567777 345677777
Output Example
1234567 2345677 3456777
Extract substring after the specified character
For String-type (multiple lines) data, splits each line, then uses replaceFirst("^[^@]+@", "") to replace the substring up to the specified character (in this sample, @) to blank, and then rejoins them together with newline characters.
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.![replaceFirst("^[^@]+@", "")], #NL)}Input Example
anderson@sub.example.com bohr@mail.example.org curie@service.example.net dirac@secure.example.com einstein@dev.portal.example.org feynman@monitor.example.net
Output Example
sub.example.com mail.example.org service.example.net secure.example.com dev.portal.example.org monitor.example.net
2.2 Extract Specific Lines
Extract only lines that contain the specified characters
Extracts only the lines that contain the specified substring (in this sample, error).
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.?[contains("error")], #NL)}Input Example
error:1 OK:2 error:3 debug:4
Output Example
error:1 error:3
Remove blank lines
Removes lines of length 0 (blank lines). This is useful for cleaning up unnecessary blank lines that are mixed in with logs or other multi-line data.
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.?[length() != 0], #NL)}Input Example
line1 line2 line3
Output Example
line1 line2 line3
Extract the first matching line
Among all the lines meeting the condition, only the first matching line is extracted. For instance, if checking for line length, you can pick just the first line of length 5 or greater.
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.^[length() >= 5], #NL)}Input Example
123 12345 abcde 999999 abcd
Output Example
12345
Extract the last matching line
Among all the lines meeting the condition, only the final matching line is extracted. This is helpful when you want to extract only one line that matches the number.
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.$[length() >= 5], #NL)}Input Example
123 12345 abcde 999999 abcd
Output Example
999999
Extract lines that begin with or end with specified character
Retrieves only those lines that start with one specified substring (for example, prefix) or end with another (for example, suffix).
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.?[startsWith('prefix') || endsWith('suffix')], #NL)}Input Example
prefix-abc some text suffix prefix and suffix middle line endswith suffix prefix
Output Example
prefix-abc some text suffix prefix and suffix endswith suffix prefix
Extract lines that match RegExp
Extracts lines that match a regular expression (RegExp) from the multiline text. A regular expression (RegExp) can be specified as the matching condition. This is convenient for extracting information with a certain pattern like postal codes or phone numbers.
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.?[matches('[0-9]{3}-[0-9]{4}')], #NL)}Input Example
602-8043 6028043 ***-**** 602-80-43
Output Example
602-8043
Extract substring after a specified character for lines matching a condition
For String-type (multiple lines) data, extracts lines containing a specified character (in this example, @) and extract substring after that character (in this example, @) .
Sample Expression
#{#joiner.join(#q_stringSample?.split(#NL)?.?[contains("@")]?.![ replaceFirst("^[^@]+@", "") ], #NL)}Input Example
anderson@sub.example.com bohr@mail.example.org mail.example curie@service.example.net
Output Example
sub.example.com mail.example.org service.example.net
Extract substring up to a specified character for lines matching a condition
For String-type (multiple lines) data, extracts lines containing a specified character (in this example, @mycompany.example.com) and extract a substring up to that character (in this example, @) .
Sample Expression
#{#joiner.join(#q_stringSample?.split(#NL)?.?[!contains("@mycompany.example.com")]?.![ replaceFirst("@.*$", "") ], #NL)}Input Example
alice@mycompany.example.com anderson@sub.example.com bohr@mycompany.example.com curie@service.example.net einstein@dev.portal.example.org
Output Example
anderson curie einstein
2.3 String Replacement
Multiple line string replacement
For the given string data, replaces all specified characters (in this example, apple) with another character (in this example, banana).
Sample Expression
#{#joiner.join(#q_stringExample?.split(#NL)?.![ replaceAll("apple","banana") ], #NL)}Input Example
apple,orange,apple melon,apple
Output Example
banana,orange,banana melon,banana
2.4 Obtain String Information
Get the number of characters
Retrieves the length (number of characters) of string-type data. This is useful for checking how much data changed before and after conversion.
Sample Expression
#{#q_stringExample?.length}Input Example
hello
Output Example
5
Get the number of lines
Gets the number of lines in String-type (multiple lines) data.. Note that blank lines are also included.
Sample Expression
#{#q_stringExample?.split(#NL)?.length}Input Example
line1 line2 line3
Output Example
3
2.5 Convert String into Specified Format
Adding prefixes and suffixes to strings
This is a sample that adds common prefixes and suffixes to each line of character-type (multiple lines) data. It can be used to convert your data into formatted list or HTML representations.
Sample Expression 1
#{#joiner.splitJoin(#q_stringExample, '<br>')}Input Example
apple orange banana strawberry
Output Example
apple<br>orange<br>banana<br>strawberry
Sample Expression 2
#{#joiner.splitJoin(#q_string_multiple, '<li>', '</li>')}Input Example
apple orange banana strawberry
Output Example
<li>apple</li><li>orange</li><li>banana</li><li>strawberry</li>
Sample Expression 3
#{#joiner.splitJoin(#q_string_multiple, '<li>', '</li>', #NL)} Input Example
apple orange banana strawberry
Output Example
<li>apple</li> <li>orange</li> <li>banana</li> <li>strawberry</li>
Conversion to XML format
The following sample demonstrates how to convert String-type (multiple lines) data into <item> tags. First, the string is split into individual lines using newline characters. Then, each line is embedded within an <item> tag as an attribute. Finally, the tagged lines are recombined with newline characters to dynamically generate XML content.
Sample Expression
<items>
#{#joiner.join(#q_stringExample?.split(#NL).![#this + '"display="' + #this], ' <item value= '',''/> ', #NL)}
</items>Input Example
apple orange banana strawberry
Output Example
<items> <item value="apple"display="apple"/> <item value="orange"display="orange"/> <item value="banana"display="banana"/> <item value="strawberry"display="strawberry"/> </items>
Conversion to HTML format
This is a sample that converts Markdown-type data into HTML format. Documents concisely formatted as Markdown syntax can be dynamically formatted and displayed as HTML format of table or list.
Sample Expression
#{#markdown.toHtml(#q_markdown_data)}Input Example
| Product name | Price | Stock | |:---------|:----:|-----:| | Notes | ¥500 | 10 | | Pen | ¥100 | 50 | | Eraser | ¥150 | 30 |
Output Example
<table> <thead> <tr> <th align="left">Product Name</th> <th align="center">Price</th> <th align="right">Stock</th> </tr> </thead> <tbody> <tr> <td align="left">Notes</td> <td align="center">¥500</td> <td align="right">10</td> </tr> <tr> <td align="left">Pen</td> <td align="center">¥100</td> <td align="right">50</td> </tr> <tr> <td align="left">Eraser</td> <td align="center">¥150</td> <td align="right">30</td> </tr> </tbody> </table>
Convert to escaped string
This is a sample that converts special characters into escaped strings for use in HTML, XML, JavaScript, JSON, Markdown, and other formats. This is useful for safely embedding code and adjusting formatting when connecting to external sources.
Sample Expression 1 (Escaped JavaScript String)
#{#escaper.escapeEcmaScript(#q_script_data)} "#escapeEcmaScript()" works the same as "#escaper.escapeEcmaScript()" .
Input Example
let greet = (name) => {
return “Congratulations! " + name;
};
console.log(greet(“Tom”)); // “Congratulations! Tom”Output Example
let greet = (name) => {\nreturn \u201CCongratulations! \u201D + name;\n};\nconsole.log(greet(\u201CTom\u201D)); \/\/ \u201CCongratulations! Tom\u201D
Sample Expression 2 (Escaped Json String)
#{#escaper.escapeJson(#q_json_data)} Input Example
[
{"Id" : "101", "Country" : "United Kingdom", "Currency" : "Pound"},
{"Id" : "102", "Country" : "Germany", "Currency" : "Euro"},
{"Id" : "103", "Country" : "Japan", "Currency" : "Yen"}
]Output Example
[\n{\"Id\" : \"101\", \"Country\" : \"United Kingdom\", \"Currency\" : \"Pound\"},\n{\"Id\" : \"102\", \"Country\" : \"Germany\", \"Currency\" : \"Euro\"},\n{\"Id\" : \"103\", \"Country\" : \"Japan\", \"Currency\" : \"Yen\"}\n]Sample Expression 3 (Escaped XML String)
#{#escaper.escapeXml(#q_xml_data)}"#escapeXml()" works the same as "#escaper.escapeXml()" .
Input Example
<continent name="Europe"> <country name="UK" language="English"> <name lang="EN">United Kingdom</name> <name lang="JA">England</name> <currency>GBP</currency> </country> <country name="Germany" language="German"> <name lang="EN">Germany</name> <name lang="JA">ドイツ</name> <currency>EUR</currency> </country> </continent>
Output Example
<continent name="Europe"> <country name="UK" language="English"> <name lang="EN">United Kingdom</name> <name lang="JA">England</name> <currency>GBP</currency> </country> <country name="Germany" language="German"> <name lang="EN">Germany</name> <name lang="JA">ドイツ</name> <currency>EUR</currency> </country> </continent>
Sample Expression 4 (Escaped HTML String)
#{#escaper.escapeHtml(#q_html_data)}Input Example
<body> <h1>This is a heading</h1> <p class="intro">This is a paragraph</p> <div class="section"> <h2>This is a subheading</h2> <p>This is a URL</p> <p>https://example.com/search?query=apple&sort=asc</p> </div> </body>
Output Example
<body> <h1>This is a heading</h1> <p class="intro">This is a paragraph</p> <div class="section"> <h2>This is a subheading</h2> <p>This is a URL</p> <p>https://example.com/search?query=apple&amp;sort=asc</p> </div> </body>
Sample Expression 5 (Markdown Escaped String)
#{#escaper.escapeMarkdown(#q_markdown_data)}"#markdown.escape()" works the same as "#escaper.escapeMarkdown()".
Input Example
| Product Name | Price | Stock | |:---------|:----:|-----:| | Notebook | ¥500 | 10 | | Pen | ¥100 | 50 | | Eraser | ¥150 | 30 |
Output Example
| Product Name | Price | Stock | |:---------|:----:|-----:| | Notebook | ¥500 | 10 | | Pen | ¥100 | 50 | | Eraser | ¥150 | 30 |
Conversion to Hash String
This is a sample that uses a hash function to generate a fixed-length hash value from a specific string. It can be used for generating IDs for identification or detecting data tampering.
Sample Expression
#{#sha256(processInstanceTitle)}Input Example
Work Request Flow
Output Example
fd10a603dd04a136032a81248e28bcad7d4ac19e39a77cfadd52dae6d04076c6
2.6 String Generation
Random String Generation
This sample generates a random alphanumeric string (0-9a-zA-Z) of a specified length. Useful for automatically generating passwords or unique identifiers.
Sample Expression
#{#randomString(12)}Output Example
pJBAzTDft8wT
2.7 Outputting Other Data Types as Strings
Outputting Selection Types as Strings
This sample formats and outputs selected values (display labels or IDs) from checkboxes or selection lists as strings. Useful for visualizing selections separated by line breaks or HTML tags.
Sample Expression 1 (Output Display Labels of Selected Items)
#{#joiner.join(#q_select_check, '<br>')}Input Example
Output Example
apple<br>orange<br>banana
Sample Expression 2 (Format and Output IDs and Display Labels of Selected Items)
#{#joiner.join(#q_select_check?.![value + ':' + display], '<li>', '</li>')}Input Example
Output Example
<li>1:apple</li><li>2:orange</li><li>3:banana</li>
Sample Expression 3 (Output IDs and Display Labels of Selected Items in HTML Format)
#{#joiner.join(#q_select_check, '<li>', '</li>', '<br>')}Input Example
Output Example
<li>1:apple</li><br><li>2:orange</li><br><li>3:banana</li>
Outputting Table Types as Strings
This sample consolidates Table-type data into a string.
It dynamically generates a formatted string by extracting values from each row, combining them with vertical bars as attributes, and finally rejoining them with newline characters. Useful for report output or log output. For detailed specifications of table-type data items, please refer to Table Type.
Sample Expression 1
#{#joiner.join(#q_table?.rows?.![#this['name'] + '|' + #this['price'] ],#NL)}Input Example
Output Example
Apple|100 Orange|200
Sample Expression 2
#{#joiner.join(#q_table?.rows?.!['Travel Expense : ' + #joiner.join(cols, ' | ')],#NL)}Input Example
Output Example
Travel Expense: Taxi | 4300 | Cash Travel Expense: Airplane | 15000 | Credit Card
3. Numeric Formatting and Operations
You can use the format() method of java.lang.String with #sformat(). For example, when outputting numeric data as strings, you can use "format specifiers" in EL expressions to convert and output data in various formats. The basic format is {padding character}{total width of the string}.{number of decimal places}f. If you specify a padding character, it will be inserted when the output digit count does not meet the total width.
If the numeric data (argument) is of an integer type such as processInstanceId or "processInstanceSequenceNumber", the conversion character becomes d instead of f, and the basic format becomes {total width of the string}d.
The formatting of decimal points, etc., depends on the locale settings of the platform:
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Formatter.html
3.1 Numeric Formatting
This section provides samples of formatting numbers into various styles using EL syntax. You can flexibly adjust formatting options such as adding positive or negative signs, or fixing the number of decimal places according to your specific needs.
Displaying signs and specifying decimal places
The following sample demonstrates how to consistently display a positive (+) or negative (−) sign and round the decimal places to a specific precision. In this example, numbers are rounded to two decimal places, always displaying the appropriate sign (+/–).
Sample Expression
#{#sformat("%+.2f", #q_numExample)}Input Example
3.14159
Output Example
+3.14
Blank Padding
Specifies the minimum width of the output and aligns digits with spaces as needed. In the sample below, no decimal places are shown—only the integer part is displayed. Useful for neatly aligned numeric output.
Sample Expression
JPY #{#sformat("% 4.0f",#q_numExample)}Input Example 1
123456.78
Output Example 1
JPY 123457
Input Example 2
-1.234
Output Example 2
JPY -1
Inserting Digit Grouping Separators
Adds a comma every three digits for improved readability of numbers like monetary values.
Sample Expression
JPY #{#sformat("%,4.0f", #q_numExample)}Input Example 1
123456.78
Output Example 1
JPY 123,457
Input Example 2
1
Output Example 2
JPY 1
Zero Padding
Fixes the total number of output characters and pads the beginning with zeros if necessary.
Sample Expression
INVOICE-#{#sformat("%04.0f", #q_numExample)}Input Example 1
123456.78
Output Example 1
INVOICE-123457
Input Example 2
1
Output Example 2
INVOICE-0001
3.2 Numeric Operations
Rounding numbers
The following sample demonstrates how to round a numeric value to a specified number of decimal places. Here, the value is rounded to two decimal places, properly formatted with negative signs and decimal points.
Sample Expression
#{#sformat("%.2f", #q_numExample)}Input Example
-1.234
Output Example
-1.23
Truncating numbers
This sample illustrates a simple method for approximate truncation or rounding of numeric values. If the input number is negative, 0.005 is added; if positive, 0.005 is subtracted. Afterward, the value is formatted to two decimal places. While this approach isn't strictly precise truncation, it's useful when you want to quickly and roughly round numbers.
Sample Expression
#{#q_numExample < 0 ? #sformat("%.2f", (#q_numExample + 0.005)) : #sformat("%.2f", (#q_numExample - 0.005))}Input Example
-1.789
Output Example
-1.78
4. Formatting and Comparing Date/Time Data
You can use com.questetra.bpms.core.event.scripttask.DateFormatWrapper with #dateFormatter. This allows you to convert date/time data to a string and and format it. You can also use the format() method of java.text.SimpleDateFormat with #format().
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/text/SimpleDateFormat.html
4.1 Formatting Date/Time Data
This section provides a sample of converting Date or Datetime data into formatted string representations.
"yyyy/MM/dd" format conversion
Sample Expression
#{#dateFormatter.format('dd mm, yyyy', #q_DateExample)}Input Example
2025-02-18
Output Example
18 02, 2025
Outputting DateTime with Explicit Time Zone
This sample formats datetime data based on a specified time zone. It's useful for displaying time including time zone differences or adjusting for different regions.
Sample Expression 1
This sample formats datetime data and appends the time zone information based on the workflow platform’s time zone. Useful when communicating with other countries or international organizations.
#{#dateFormatter.format('yyyy-MM-dd HH:mmz', #q_datetime)}Input Example
2021-04-12 09:45
Output Example
2021-04-12 09:45+0900
Sample Expression 2
This sample converts and formats datetime data from the workflow platform’s time zone to a specified time zone and appends the time zone info for display. Useful when contacting specific countries.
#{#dateFormatter.format('GMT-0900', 'EEE. dd. MMMM, yyyy HH:mmZ', #q_datetime)}Input Example
2021-04-12 09:45
Output Example
Mon. 11. April, 2021 15:45-0900
4.2 Comparing Dates
This section demonstrates how to compare two dates provided as strings by converting them into Date-type data. Since comparison operators (<, >) cannot be used directly on strings, always convert the strings into dates before comparison.
Determining the Chronological Order of Two Dates
Sample Expression
#{#dateFormatter.parse("yyyy-MM-dd", #q_DateExample1) < #dateFormatter.parse("yyyy-MM-dd", #q_DateExample2)
? "Date1 is earlier"
: "Date1 is later or the same date"
}Input Example (q_DateExample1)
2025-01-01
Input Example (q_DateExample2)
2025-02-01
Output Example
Date1 is earlier
Combining Date Formatting and Comparison
This sample compares two dates and outputs the earlier date as a string in dd mm, yyyy format.
Sample Expression
#{#dateFormatter.parse("yyyy-MM-dd", #q_DateExample1) < #dateFormatter.parse("yyyy-MM-dd", #q_DateExample2)
? #dateFormatter.format('dd mm, yyyy', #q_DateExample1)
: #dateFormatter.format('dd mm, yyyy', #q_DateExample2)}Input Example (q_DateExample1)
1998-07-24
Input Example (q_DateExample2)
1996-06-23
Output Example
23 06, 1996
4.3 Calculating Time/Date Differences
This section demonstrates how to calculates the difference between two date/time data points.
Outputting in Hours
This sample calculates the difference between two dates and times, then outputs the result as a string in hours, rounded to two decimal places.
Sample Expression
#{#sformat("%.2f", (#q_TimeExample2.getTime() - #q_TimeExample1.getTime()) / 3600000.0)}
Input Example (q_TimeExample1)
2025-09-03 09:15
Input Example (q_TimeExample2)
2025-09-03 17:30
Output Example
8.25