XLSForm None of the Above in select_multiple
To make "None of the above" exclusive in an XLSForm select_multiple question, set the constraint to not(selected(., '0')) or count-selected(.) = 1, where 0 is the name of the None choice. It reads: either None is not ticked, or it is the only thing ticked. ODK, KoboToolbox and SurveyCTO all evaluate it the same way, and every example on this page compiles with pyxform and ODK Validate.
What is the constraint for an exclusive None option?
A select_multiple answer is a space-separated list of the choice names that were ticked, such as 1 4. The constraint runs when the enumerator tries to move on, and it checks that list. In a constraint, . means "this question's answer".
| type | name | label | hint | required | constraint | constraint_message |
|---|---|---|---|---|---|---|
| select_multiple shock | shocks | Which of these shocks did the household face in the last 12 months? | Select all that apply, or choose None. | yes | not(selected(., '0')) or count-selected(.) = 1 | None cannot be combined with another answer. |
| list_name | name | label |
|---|---|---|
| shock | 1 | Drought or flood |
| shock | 2 | Crop pest or disease |
| shock | 3 | Death of livestock |
| shock | 4 | Job loss or illness of the main earner |
| shock | 5 | Sharp rise in food prices |
| shock | 0 | None of the above |
Two functions do the work:
selected(., '0')is true when the choice named0is among the ticked options.count-selected(.)is the number of options ticked.
The form blocks the swipe only when None is ticked and something else is too. Ticking only None passes, and ticking several real options without None passes.
How do I make both None and Don't know exclusive?
Surveys often carry two exclusive answers: "None" and "Don't know". Neither may be combined with a real answer. Test for either one, then require a single selection:
| type | name | label | required | constraint | constraint_message |
|---|---|---|---|---|---|
| select_multiple symptom | symptoms | Which symptoms does the child have today? | yes | count-selected(.) = 1 or not(selected(., '0') or selected(., '-99')) | None and Don't know must be the only answer, or choose real symptoms. |
| list_name | name | label |
|---|---|---|
| symptom | 1 | Fever |
| symptom | 2 | Cough |
| symptom | 3 | Diarrhoea |
| symptom | 4 | Vomiting |
| symptom | 5 | Skin rash |
| symptom | 0 | None of these |
| symptom | -99 | Don't know |
This still allows "None" alone and "Don't know" alone, but not "None" with "Don't know", because that would mean two ticks. The same pattern extends to a third exclusive option such as Refused: add or selected(., '-98') inside the not(...).
How do I limit selections to a maximum and keep None exclusive?
This is a frequent forum question: allow up to 3 answers, but only 1 when None is chosen. Join the two rules with and:
| type | name | label | hint | required | constraint | constraint_message |
|---|---|---|---|---|---|---|
| select_multiple crop | crops | Which crops did the household grow this season? | Choose up to 3 crops. | yes | count-selected(.) <= 3 and (count-selected(.) = 1 or not(selected(., '0'))) | Choose up to 3 crops, or only 'Did not grow any crops'. |
| list_name | name | label |
|---|---|---|
| crop | 1 | Maize |
| crop | 2 | Rice |
| crop | 3 | Beans |
| crop | 4 | Cassava |
| crop | 5 | Groundnut |
| crop | 6 | Vegetables |
| crop | 0 | Did not grow any crops |
One constraint message covers both failures, so write it to name both rules. If you only need the maximum, count-selected(.) <= 3 on its own is enough. More validation patterns are in the XLSForm constraint examples.
Why add a None option instead of letting people skip?
If the question is optional and an enumerator leaves it empty, you cannot tell "the household had no shocks" from "the enumerator forgot". An explicit None option removes the doubt: every completed interview has a real answer. So pair the None choice with required set to yes, as every example above does.
Do not let the empty answer stand in for None, and do not drop required to "make it easier". The analysis then splits into three groups (some, none, missing) instead of two.
How do I use the None answer in later questions?
Treat None as a normal choice in later rules. Ask a follow-up only when the household reported at least one shock, and count shocks without counting None itself:
| type | name | label | required | relevant | constraint | constraint_message | choice_filter | calculation |
|---|---|---|---|---|---|---|---|---|
| select_multiple shock | shocks | Which of these shocks did the household face in the last 12 months? | yes | not(selected(., '0')) or count-selected(.) = 1 | None cannot be combined with another answer. | |||
| select_one shock | worst_shock | Which shock hurt the household most? | yes | not(selected(${shocks}, '0')) | name != '0' | |||
| calculate | shock_count | if(selected(${shocks}, '0'), 0, count-selected(${shocks})) | ||||||
| note | show_count | Shocks reported: ${shock_count} |
| list_name | name | label |
|---|---|---|
| shock | 1 | Drought or flood |
| shock | 2 | Crop pest or disease |
| shock | 3 | Death of livestock |
| shock | 4 | Job loss or illness of the main earner |
| shock | 5 | Sharp rise in food prices |
| shock | 0 | None of the above |
worst_shock is skipped when None is ticked, and its choice_filter of name != '0' removes None from the list it shows. Because the earlier constraint guarantees None is alone, shock_count is either 0 or the number of real shocks. Skip logic on a select_multiple question covers the relevant side in more depth.
The mistake that compiles is comparing with = or !=. On a select_multiple question, . != '0' is also true for 0 1, because the whole string 0 1 is not equal to 0. The constraint then blocks nothing and no error appears. Always use selected() and count-selected().
Common mistakes and the errors you will see
The messages below come from ODK Validate, which ODK Central, KoboToolbox and the XLSForm converter run when a form is uploaded:
| You wrote | Write instead | Error you will see |
|---|---|---|
selected(., '0') && count-selected(.) = 1 | selected(., '0') and count-selected(.) = 1 | Couldn't understand the expression starting at this point |
not selected(., '0') or count-selected(.) = 1 | not(selected(., '0')) or count-selected(.) = 1 | Couldn't understand the expression starting at this point |
count-selected(.) <= 3 AND not(...) | count-selected(.) <= 3 and not(...) | Couldn't understand the expression starting at this point |
count-selected(.) =< 3 | count-selected(.) <= 3 | Bad node |
. != '0' on a select_multiple | not(selected(., '0')) | No error, but nothing is blocked |
and, or and not() are XPath words: lowercase, with not written as a function. For other messages, see common XLSForm errors, or paste the form into the free XLSForm validator.
Does this work the same in ODK, KoboToolbox and SurveyCTO?
Yes. selected() and count-selected() are standard XPath functions in all three, so the constraint text is identical. Only the place you type it differs:
| Platform | Where the constraint goes |
|---|---|
| ODK (XLSForm) | constraint column, with the sentence in constraint_message |
| KoboToolbox (XLSForm upload) | Same as ODK |
| KoboToolbox Formbuilder | The question's Validation criteria setting |
| SurveyCTO | constraint column of the form definition |
A form that follows this page moves between the three platforms with its logic intact.
Where exclusive options pay off in the field
An enumerator who has just heard "none of those" can still tick a real option by accident, and the dataset then says a household had no shocks and a drought. That contradiction takes hours to find in Stata or R and cannot be fixed after the interview. The constraint stops it while the respondent is still in the room.
Describe the rule in plain language: "None of the above must be the only answer, and allow at most 3 other options." LooprAI writes the constraint and the message, then compiles the form with pyxform before saving, so a missing parenthesis never reaches your enumerators.
Next: XLSForm constraint examples →
Frequently Asked Questions
How do I stop None from being selected with other options in XLSForm?
Add a constraint to the select_multiple question: not(selected(., '0')) or count-selected(.) = 1, where 0 is the name of the None choice. The form then refuses to move on when None is ticked together with any other option.
How do I limit a select_multiple question to 3 answers in XLSForm?
Use count-selected(.) <= 3 in the constraint column and write a constraint message such as 'Choose no more than 3.' To keep None exclusive as well, join both rules with and and wrap the None test in parentheses.
How do I make both None and Don't know exclusive?
Use count-selected(.) = 1 or not(selected(., '0') or selected(., '-99')). It passes when only one option is ticked, or when neither exclusive option is ticked. Add another or selected(...) inside not() for a third option such as Refused.
Why does my None constraint not block anything?
You probably compared with = or != instead of selected(). A select_multiple answer is a space-separated list, so . != '0' is also true for the answer '0 1'. Switch to selected(., '0') and count-selected(.), which read the list correctly.
Should the None option be required?
Yes. Set required to yes so every completed interview has a real answer. If the question is optional, an empty value could mean no or skipped by mistake, and you cannot tell the two apart during analysis.
Is the None constraint the same in KoboToolbox and SurveyCTO?
Yes. ODK, KoboToolbox and SurveyCTO all support selected() and count-selected(), so the same constraint text works in each. In XLSForm and SurveyCTO it goes in the constraint column; in Kobo's Formbuilder use the question's Validation criteria.
No Credit Card Required
Build the form first. Add hosting when you need it.
Start free with LooprAI, then deploy a managed ODK Central server or run DataSnap checks when your project is ready.
Automation handles the mechanical work.
Researchers decide what the evidence means.