- Home
- Documentation
- Designing forms
- Expressions and logic
Designing forms
Expressions and logic
Referring to answers, relevance, constraints, calculations, repeat groups and choice filters, and where Joripo follows SurveyCTO rather than plain XPath.
Joripo documentation · https://joripo.com/docs/designing-forms/expressions
On this page
Relevance, constraints, calculations, choice filters, repeat counts and defaults are all expressions: small formulas in the language SurveyCTO and ODK share (XPath, with SurveyCTO's functions added). The function reference lists every function and where each one works.
Referring to answers
${name} is the answer to the question called name. In a constraint, . is the answer being checked.
${age} >= 18 and selected(${services}, 'anc')
. <= ${hh_size}
if(${consent} = 1, 'yes', 'no')
The operators are =, !=, >, >=, <, <=, and, or, +, -, *, div and mod. Text goes in single quotes. A question nobody answered is the empty string ''.
Relevance
A relevance expression decides whether a question, a group or a repeat is asked at all. A question that is not relevant is skipped, its answer is left out of the submission, and it exports blank. A group's relevance applies to everything inside it.
Constraints and required answers
A constraint is checked when the enumerator moves on, and only when there is an answer: an empty answer is a matter for required, not for the constraint. A broken constraint stops them with the constraint message, or "That entry is invalid" when there is none. A required question left blank stops them with the required message, or "Sorry, this response is required!".
A constraint Joripo cannot read is reported as a warning at upload, as SurveyCTO does: the form deploys, and that answer is not checked.
Calculations
- A
calculaterow is recalculated whenever an answer it reads changes. - A
calculate_hererow is worked out once, when the enumerator reaches it: the way to record when a section began. - A
calculationon a question the enumerator can edit is a calculated default: given the first time the question is shown, then theirs to change. On a note, or on a question markedread only, it stays live instead. once(...)keeps the first value it gave: use it aroundrandom()anduuid()so they do not change every time the form recalculates.
A calculation and a relevance condition that depend on each other in a loop are refused at upload, naming the rows, as SurveyCTO refuses them. The exception is the loop SurveyCTO itself allows in "ask once" designs and garbling, where a calculate_here copies an answer that is still blank; Joripo treats it as SurveyCTO does.
Repeat groups
Inside a repeat group, ${field} of the same repeat means this instance's answer: the current household member's age, not every member's. From outside the repeat, ${field} means every instance at once, so you use a function that takes many values:
count(${members}),sum(${income}),min(...),max(...),join(', ', ${name});count-if(...),sum-if(...),join-if(...)and the other-iffunctions, whose condition is checked for each instance;indexed-repeat(${name}, ${members}, 2)for one instance's answer; a number past the last instance gives a blank;index()for the number of the instance you are in.
Choice filters
A choice_filter keeps only the choices for which it is true. It can refer to the form's answers and to any column of the choices sheet: with a district column on the choices of upazila, the filter district = ${district} offers only that district's upazilas. It works inside repeat groups too.
Dates and times
In arithmetic a date is a number of whole days since 1 January 1970, so today() + 1 is tomorrow and ${end_date} - ${start_date} is a number of days. format-date-time() writes one out in any layout. duration() is the number of seconds the form has been open, as SurveyCTO counts it: time a saved draft sat closed is left out, and so is time the app spent in the background.
Where Joripo follows SurveyCTO rather than XPath
SurveyCTO's forms run on JavaRosa, and where JavaRosa and plain XPath disagree, Joripo does what SurveyCTO does. These were found by replaying real SurveyCTO submissions and comparing the data cell by cell, not by reading documentation:
- a calculation that is true or false is stored as
1or0; ${n}-1is a subtraction, not a field calledn-1;indexed-repeat()past the last instance is blank;jr:choice-name()on a question that is not a choice question is blank;- a multiple-choice answer from a field plug-in keeps its order.
Checked before you deploy
The upload checks every expression and names the sheet, row and column of any it cannot read. The form designer runs the same checks as you type. An expression pasted from a web page or Word sometimes carries a no-break space: Joripo reads it as an ordinary space, as SurveyCTO does. Other unusual spaces (zero-width, ideographic) are refused with the row and column, as SurveyCTO refuses them.