Functions can be used to validate syntax, calculate values, transform data, and control workflow.
Much of the content below is borrowed and adapted under the Creative Commons license from Get ODK. Note: OpenClinica does not support every function listed on the Get ODK website. Review the full list of functions that have been validated and tested in OpenClinica in the OpenClinica Validated Functions Index.
General Functions
Conditional (if statements)
| Description: | Evaluates expression, if the expression is true it returns or executes the then statement, if the expression evaluates to false it returns/executes the else statement. |
| Syntax: | if(expression, then, else) |
| Example: | if(${ae_death} = 'yes', 'SAE', if(${ae_hospital} = 'yes', 'SAE', if(...))) This nested if statement will eventually cascade through the entire SAE criteria list to see if any were answered 'Yes', and if so it will return 'SAE', if not then it will move to the next criteria and so-on. The last statement should return 'false' or similar negative value. |
Once (run something once)
| Description: | Returns the value defined by expression if the question's value is empty. Otherwise, returns the current value of the question. This can be used to ensure that a random number is only generated once, or to store the first value entered for a question in a way that is retrievable even if the response is changed later. |
| Syntax: | once(expression) |
| Example: | once(today()) Instead of using once(), you could also if(. != '', today(), .). If it's not empty, do expression. Otherwise, leave unchanged. |
Selected (see if something was selected)
| Description: | Checks whether string2 appears in string1, where string1 is a space-separated list of values. Either or both could be item references instead of hard-coded string literals. |
| Syntax: | selected(string1, string2) |
| Example: | selected(${diagnoses}, 'cancer') not(selected(., 'c') or selected(., 'd')) Note: Can be used as a shortcut for writing many or clauses. For example, selected('a b c d e', .) is a shortcut for ". = 'a' or . = 'b' or . = 'c' or . = 'd' or . = 'e'." This could be useful in if() statements, relevant logic, etc. |
Count Selected (count number of selected choices)
| Description: | Returns the number of choices selected in a multiple choice question. |
| Syntax: | count-selected(select_multiple_item_name) |
| Example: | count-selected(${days_sick}) |
Functions for Repeating Data Structures
Max
| Description: | Returns the largest member of nodeset. Only works on sets of numbers. Empty values (that is, variables referencing unanswered questions) are actually empty strings, and will not be automatically converted to zero (0). Learn more about Null Values in Form Logic. |
| Syntax: | max(nodeset) |
| Example: | In the below example form definition, the calculation max(${child_age}) would return the largest age of all the ages in the repeating item group. If you wanted to see if one of the children was, say 5 years old, you could use the join or concat function to produce a string of all the responses, then use this string as the argument for the selected function. For use with repeating item data from a different form, the max function can be used directly as part of the cross-form data pull. In this example, the largest value of the item from all repeats would be returned: max(instance('clinicaldata')/ODM/ClinicalData/SubjectData/StudyEventData[@StudyEventOID='Event OID Here']/FormData[@FormOID='Form OID Here']/ItemGroupData[@OpenClinica:ItemGroupName='Item Group Name Here']/ItemData[@OpenClinica:ItemName='Item Name Here']/@Value) |
| type | name | label | calculation |
|---|---|---|---|
| begin_repeat | child_questions | Questions about child | |
| text | child_name | Child's name | |
| integer | child_age | Child's age | |
| end_repeat | |||
| calculate | age_of_oldest_child | max(${child_age}) |
Min
| Description: | Returns the smallest member of nodeset. Only works on sets of numbers. Empty values (that is, variables referencing unanswered questions) are actually empty strings, and will not be automatically converted to zero (0). Learn more about Null Values in Form Logic. |
| Syntax: | min(nodeset) |
| Example: | In the below example, the calculation min(${child_age}) would return the lowest age of all the ages in the repeating item group. |
| type | name | label | calculation |
|---|---|---|---|
| begin_repeat | child_questions | Questions about child | |
| text | child_name | Child's name | |
| integer | child_age | Child's age | |
| end_repeat | |||
| calculate | age_of_oldest_child | max(${child_age}) |
Sum repeats
| Description: | Returns the sum of the members of nodeset. Can be used to tally responses to a repeated select question. |
| Syntax: | sum(nodeset) |
| Example: | The below example uses this function to tally the number of meal preference. |
| type | name | label | calculation |
|---|---|---|---|
| begin_repeat | guest_details | Guest details | |
| text | guest_name | Guest name | |
| select_one_meal_options | meal_preference | Meal preference | |
| calculate | chkn | if(${meal_preference} = 'chicken', 1, 0 ) | |
| calculate | fsh | if(${meal_preference} = 'fish', 1, 0 ) | |
| calculate | veg | if(${meal_preference} = 'vegetarian', 1, 0 ) | |
| end_repeat | |||
| calculate | chkn_count | sum(${chkn}) | |
| calculate | fsh_count | sum(${fsh}) | |
| calculate | veg_count | sum(${veg}) |
Count repeats
| Description: | Returns the sum of the members of nodeset. Can be used to tally responses to a repeated select question. |
| Syntax: | count(nodeset) |
| Example: | The below example asks the user for the number of family members, then uses the count function to ensure follow-up questions are asked once per each family member. |
| type | name | label | repeat_count | calculation |
|---|---|---|---|---|
| note | person_list_note | Please list the names of the people in your household. | ||
| begin_repeat | person | Member of household | ||
| text | name | Name | ||
| end_repeat | ||||
| begin_repeat | person_details | Details | count(${person}) | |
| calculate | current_name | indexed-repeat(${name}, ${person}, position(..)) | ||
| date | member_bday | Birthday of ${current_name} | ||
| end_repeat |
Count non-empty repeats
| Description: | Returns the number of non-empty members of nodeset. |
| Syntax: | count-non-empty(nodeset) |
| Example: | count-non-empty(${bp_sys}) If a user adds a repeating group occurrence but does not put data into any of its fields, the count() function would increase by 1, but the count-non-empty() function would not increase. |
Indexed Repeat
| Description: | Returns a particular iteration of a repeating value. |
| Syntax: | indexed-repeat(item_name, repeating_group_name, iteration) item_name is the variable you want to retrieve |
| Example: | indexed-repeat(${bp_diastolic}, ${bp_rg}, ${bp_number}) When used as a calculation, returns the diastolic pressure from a specific repeat instance, where:
|
Position
| Description: | Returns an integer equal to the position of the current node within the node defined by xpath. The first entry has a position of 1, second entry 2, and so on. Most often this is used in the form position(..) to identify the current iteration within a repeating group. |
| Syntax: | position(xpath) |
| Example: | position(..) |
| type | name | label | repeat_count | calculation |
|---|---|---|---|---|
| begin_repeat | ||||
| calculate | med_num | position(..) | ||
| text | name | Please enter the name of medication # ${med_num} | ||
| end_repeat |
String functions
Concatenate (combine values)
| Description: | Concatenates one or more arguments into a single string. If any arg is a nodeset, the values within the set are concatenated into a string. |
| Syntax: | concat(arg1, arg2, arg3...) |
| Example: | concat(${yyyy},'-',${mm},'-',${dd}) concat(${temp},' ⁰C') |
Convert to String (transform data type)
| Description: | Converts arg to a string. |
| Syntax: | string(arg) |
Regular Expression (validate syntax)
| Description: | Returns True if the string is an exact and complete match for the expression. Regular expressions provide a standardized way of validating the syntax of data entered. |
| Syntax: | regex(string, expression) string is the value you want to apply the regular expression to |
| Example: | regex(., '([01][0-9]|2[0-3]):[0-5][0-9]') and string-length(.) = 5 regex(., '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}') |
Substring (parse a string)
| Description: | Returns the substring of string beginning at the index start and extending to (but not including) index end (or to the termination of string, if end is not provided). |
| Syntax: | substr(string, start, end) Members of string are zero-indexed, so the first character of the string has index value of 0, the second character an index value of 1, etc. |
| Example: | substr(${date}, 0, 4) |
Substring Before (parse a string)
| Description: | Returns the substring of string before the first occurrence of the target substring. If the target is not found, or string begins with the target substring, then this will return an empty string. |
| Syntax: | substring-before(string, target) |
| Example: | substr-before(${kit_num}, '-') |
Substring After (parse a string)
| Description: | Returns the substring of string after the first occurrence of the target substring. If the target is not found this will return an empty string. |
| Syntax: | substring-after(string, target) |
| Example: | substr-after(${kit_num}, '-') |
String Length (count characters in a string)
| Description: | Returns the number of characters in string. If no value is passed in, returns the number of characters in the value of the question that this function call is tied to which can be useful in a constraint expression. |
| Syntax: | string-length(string) |
| Example: | substr(., string-length(.) - 4, string-length(.)) = ".pdf" or substr(., string-length(.) - 4, string-length(.)) = ".PDF" Ensures only PDF files are uploaded when used as a constraint on a file field. The substring function first gets the last 4 characters of the file name. Then it checks to see if the PDF file extension is all lowercase or uppercase. |
Translate
| Description: | Returns a copy of a string where every occurrence of a specified character is replaced by a new character. |
| Syntax: | translate(string, fromchars, tochars) string is the item you want to translate If fromchars is longer than tochars then every occurrence of a character in fromchars that does not have a corresponding character in tochars will be removed from the string. |
| Example: | translate(substr(., string-length(.) - 4, string-length(.)), 'pdf', 'PDF') = '.PDF' When used as a constraint on a file field, ensures the files with a PDF extension are uploaded, regardless of the case in which the file extension is written. The substring function first gets the last 4 characters of the file name. Then it checks to see if the PDF file extension is all lowercase or uppercase. translate(${input_item}, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') OpenClinica reads in cross form data from a select_multiple item as a comma separated list. However, if you want to treat this as a select_multiple value on the form you read it into, it must be treated as a space separated list. For example, the following expression would convert these values into a space separated string upon reading it into the form: translate(instance('clinicaldata')/ODM/ClinicalData/SubjectData/StudyEventData[@StudyEventOID='Event OID Here']/FormData[@FormOID='Form OID Here']/ItemGroupData[@OpenClinica:ItemGroupName='Item Group Name Here']/ItemData[@OpenClinica:ItemName='Item Name Here']/@Value, ',', ' ') |
Math functions and number handling
Negation
| Description: | |
| Syntax: | not(expression) |
| Example: |
Truncate decimal
| Description: | Truncates the fractional portion of a decimal number to return an integer. |
| Syntax: | int(number) |
| Example: | int(${age}) |
Convert to Number
| Description: | Converts arg to number value. If arg is a string of digits, returns the number value. If arg is True, returns 1. If arg is False, returns 0. If arg cannot be converted, returns NaN (not a number). |
| Syntax: | number(arg) |
| Example: | number(${year}) |
Round
| Description: | Rounds a decimal number to some number of decimal places. |
| Syntax: | round(number, # places) |
| Example: | round(${pi}, 4) |
Random Number
| Description: | Returns a random number between 0.0 (inclusive) and 1.0 (exclusive). |
| Syntax: | random() |
| Example: | once(round(random()*3+1,0)) The above expression would return an integer of either 1, 2, or 3, and could thus be used to randomly assign participants to one of three groups. The following logic could then be used to map the output of the above function to one of the three groups: if(${rndm} = 1,'A', if(${rndm} = 2,'B', 'C')) |
Date and Time
Current Date
| Description: | Returns the current date without a time component. |
| Syntax: | today() |
| Example: | The expression . <= today() could be used in a constraint to ensure the date entered is not a future date. |
Current Date and Time
| Description: | Returns the current date and time with the timezone. |
| Syntax: | now() |
| Example: | For example, this can be used to set the current date and time as default. |
Decimal Time
| Description: | Converts time to a number representing a fractional day. |
| Syntax: | decimal-time(time) |
| Example: | For example,
|
Formatting Dates
| Description: | Returns date as a string formatted as defined by format. |
| Syntax: | format-date(date, format) |
| Example: | format-date(${date},‘%d-%b-%Y’) If ${date} = 2028-11-06 would return 06-Nov-2028 Month and day abbreviations are language and locale specific. If form locale can be determined, that locale will be used. Otherwise, the device locale will be used. |
| Code | Meaning |
|---|---|
| %Y | 4-digit year |
| %y | 2-digit year |
| %m | 0-padded month |
| %n | numeric month |
| %b | short text month (Jan, Feb, Mar…) |
| %d | 0-padded day of month |
| %e | day of month |
| %a | short text day (Sun, Mon, Tue…) |
Formatting Date + Time
| Description: | Returns dateTime as a string formatted as defined by format. |
| Syntax: | format-date-time(dateTime, format) |
| Example: |
The identifiers list in format-date() are available, plus the following:
| Code | Meaning |
|---|---|
| %H | 0-padded hour (24-hr time) |
| %h | hour (24-hr time) |
| %M | 0-padded minute |
| %S | 0-padded second |
| %3 | 0-padded millisecond ticks |
Calculations
Power/Exponent
| Description: | Raises number to a power |
| Syntax: | pow(number, power) |
| Example: | pow(2,3) |
Log
| Description: | Returns the natural log of number. |
| Syntax: | log(number) |
| Example: | log(30) |
Log Base-10
| Description: | Returns the base-10 log of number. |
| Syntax: | log10(number) |
| Example: | log10(30) |
Absolute Value
| Description: | Returns the absolute value of number. |
| Syntax: | abs(number) |
| Example: | abs(-5.23) |
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article