Skipping if same choice is selected for multiple questions

What is the problem? Please be detailed.

What ODK tool and version are you using? And on what device and operating system version?

What steps can we take to reproduce the problem?

What you have you tried to fix the problem?

Anything else we should know or have? If you have a test form or screenshots or logs, attach here.
Hello,
I have several questions that have multiple choices but with one choice same across all the questions (D. NONE). I would like to build a skip such that selecting D should lead to a specific part of the form. How can I do that without listing all the labels of the questions in the 'relevant' column. I was asuming something like ${Q1:40}=4 can do that but that doesnot work. Thanks

Hi @Ermias

could you attach a sample form? It's always easier to understand a problem and find a solution then.

If I understand well you need to put questions you may want to skip in one group and in relevant column check the answer from that (first) question. But maybe I missed something, that's why I asked for a sample form.

Assuming your select_multiple option "D. None" has the value 4, try this:

relevant="selected(${Q1},'4')"

See selected() for details.

Oh, if Q1 is instead a select_one, then you can get by with just this, since it can only ever take a single value:

relevant=" ${Q1}='4' "

Thank you @Grzesiek2010 and @Xiphware for looking up my question. Let me try to put it this way: I have 400 questions some of them are grouped and others not, some of the questions have four, five or six multiple choices but all of the questions have one common choice which is '16. NONE' (I assigned it to have the same label (16) regardless of the quesiton.
My challenge:
I would like to skip to a specific part of the questionnaire if '16. NONE' is selected in any of the quesitions. Under 'relevant' column of the section that I want to skip to, I can put ${Q1}=16 or ${Q2}=16 or...${Q400}=16. But is there a short way to do this instead of listing the 'names' of all 400+ questions in the relevant column?

So, for example, your form contains:
4 select questions with none option
then other question

and if in question 1 you select none you want to skip questions 2, 3, 4
if in 2 you select none you want to skip questions 3 and 4 etc.

am I right?

Thats correct. Selection of 'NONE" choice from any question should skip to , say, question 401 (last group of questions).
Thanks
Ermias

I would do something like this: noneTest.xlsx (7.1 KB)

I know it may be annoying to build such a form if you want to skip even 100 questions but I can't see a better solution.

Unfortunately, I haven't figured out how to do this yet myself.

One thing that xpath 1.0 (what ODK uses) is missing that later versions of it have is an iteration syntax. For example, it'd be nice if there was a syntax like:

for question in xform_questions():
    if(question='16', 1, 0)

Even if there was this iteration syntax, you'd still need something like a built-in function like the one I called "xform_questions()" which would pull up a list of all the questions for you, but there is no built-in function like that.

When my colleague's and I have faced this issue in the past, we've done the ugly route you're suggesting. Just make a huge code block referencing everything.

My suggested solution would be to create a calculate named something like "NONE_was_selected". Then, for all of your questions, make sure to add the condition not(${NONE_was_selected}). Finally, after all of the questions, create your warning/error/guidance screen , and set its relevant to ${NONE_was_selected}.

Normally when I need to create a huge block of logic like this, I use excel in combination w/ a text editor. Like so:

03%20PM

${Q1}=16 or 
${Q2}=16 or 
${Q3}=16 or 
${Q4}=16 or 
${Q5}=16 or 
${Q6}=16 or 
${Q7}=16 or 
${Q8}=16 or 
${Q9}=16 or 
${Q10}=16 or 
${Q11}=16 or 
${Q12}=16 or 
${Q13}=16 or 
${Q14}=16 or 
${Q15}=16 or 
${Q16}=16 or 
${Q17}=16 or 
${Q18}=16 or 
${Q19}=16 or 
${Q20}=16 or 
${Q21}=16 or 
${Q22}=16 or 
${Q23}=16 or 
${Q24}=16 or 
${Q25}=16 or 
${Q26}=16 or 
${Q27}=16 or 
${Q28}=16 or 
${Q29}=16 or 
${Q30}=16 or 
${Q31}=16 or 
${Q32}=16 or 
${Q33}=16 or 
${Q34}=16 or 
${Q35}=16 or 
${Q36}=16 or 
${Q37}=16 or 
${Q38}=16 or 
${Q39}=16 or 
${Q40}=16 or 
${Q41}=16 or 
${Q42}=16 or 
${Q43}=16 or 
${Q44}=16 or 
${Q45}=16 or 
${Q46}=16 or 
${Q47}=16 or 
${Q48}=16 or 
${Q49}=16 or 
${Q50}=16 or 
${Q51}=16 or 
${Q52}=16 or 
${Q53}=16 or 
${Q54}=16 or 
${Q55}=16 or 
${Q56}=16 or 
${Q57}=16 or 
${Q58}=16 or 
${Q59}=16 or 
${Q60}=16 or 
${Q61}=16 or 
${Q62}=16 or 
${Q63}=16 or 
${Q64}=16 or 
${Q65}=16 or 
${Q66}=16 or 
${Q67}=16 or 
${Q68}=16 or 
${Q69}=16 or 
${Q70}=16 or 
${Q71}=16 or 
${Q72}=16 or 
${Q73}=16 or 
${Q74}=16 or 
${Q75}=16 or 
${Q76}=16 or 
${Q77}=16 or 
${Q78}=16 or 
${Q79}=16 or 
${Q80}=16 or 
${Q81}=16 or 
${Q82}=16 or 
${Q83}=16 or 
${Q84}=16 or 
${Q85}=16 or 
${Q86}=16 or 
${Q87}=16 or 
${Q88}=16 or 
${Q89}=16 or 
${Q90}=16 or 
${Q91}=16 or 
${Q92}=16 or 
${Q93}=16 or 
${Q94}=16 or 
${Q95}=16 or 
${Q96}=16 or 
${Q97}=16 or 
${Q98}=16 or 
${Q99}=16 or 
${Q100}=16 or 
${Q101}=16 or 
${Q102}=16 or 
${Q103}=16 or 
${Q104}=16 or 
${Q105}=16 or 
${Q106}=16 or 
${Q107}=16 or 
${Q108}=16 or 
${Q109}=16 or 
${Q110}=16 or 
${Q111}=16 or 
${Q112}=16 or 
${Q113}=16 or 
${Q114}=16 or 
${Q115}=16 or 
${Q116}=16 or 
${Q117}=16 or 
${Q118}=16 or 
${Q119}=16 or 
${Q120}=16 or 
${Q121}=16 or 
${Q122}=16 or 
${Q123}=16 or 
${Q124}=16 or 
${Q125}=16 or 
${Q126}=16 or 
${Q127}=16 or 
${Q128}=16 or 
${Q129}=16 or 
${Q130}=16 or 
${Q131}=16 or 
${Q132}=16 or 
${Q133}=16 or 
${Q134}=16 or 
${Q135}=16 or 
${Q136}=16 or 
${Q137}=16 or 
${Q138}=16 or 
${Q139}=16 or 
${Q140}=16 or 
${Q141}=16 or 
${Q142}=16 or 
${Q143}=16 or 
${Q144}=16 or 
${Q145}=16 or 
${Q146}=16 or 
${Q147}=16 or 
${Q148}=16 or 
${Q149}=16 or 
${Q150}=16 or 
${Q151}=16 or 
${Q152}=16 or 
${Q153}=16 or 
${Q154}=16 or 
${Q155}=16 or 
${Q156}=16 or 
${Q157}=16 or 
${Q158}=16 or 
${Q159}=16 or 
${Q160}=16 or 
${Q161}=16 or 
${Q162}=16 or 
${Q163}=16 or 
${Q164}=16 or 
${Q165}=16 or 
${Q166}=16 or 
${Q167}=16 or 
${Q168}=16 or 
${Q169}=16 or 
${Q170}=16 or 
${Q171}=16 or 
${Q172}=16 or 
${Q173}=16 or 
${Q174}=16 or 
${Q175}=16 or 
${Q176}=16 or 
${Q177}=16 or 
${Q178}=16 or 
${Q179}=16 or 
${Q180}=16 or 
${Q181}=16 or 
${Q182}=16 or 
${Q183}=16 or 
${Q184}=16 or 
${Q185}=16 or 
${Q186}=16 or 
${Q187}=16 or 
${Q188}=16 or 
${Q189}=16 or 
${Q190}=16 or 
${Q191}=16 or 
${Q192}=16 or 
${Q193}=16 or 
${Q194}=16 or 
${Q195}=16 or 
${Q196}=16 or 
${Q197}=16 or 
${Q198}=16 or 
${Q199}=16 or 
${Q200}=16 or 
${Q201}=16 or 
${Q202}=16 or 
${Q203}=16 or 
${Q204}=16 or 
${Q205}=16 or 
${Q206}=16 or 
${Q207}=16 or 
${Q208}=16 or 
${Q209}=16 or 
${Q210}=16 or 
${Q211}=16 or 
${Q212}=16 or 
${Q213}=16 or 
${Q214}=16 or 
${Q215}=16 or 
${Q216}=16 or 
${Q217}=16 or 
${Q218}=16 or 
${Q219}=16 or 
${Q220}=16 or 
${Q221}=16 or 
${Q222}=16 or 
${Q223}=16 or 
${Q224}=16 or 
${Q225}=16 or 
${Q226}=16 or 
${Q227}=16 or 
${Q228}=16 or 
${Q229}=16 or 
${Q230}=16 or 
${Q231}=16 or 
${Q232}=16 or 
${Q233}=16 or 
${Q234}=16 or 
${Q235}=16 or 
${Q236}=16 or 
${Q237}=16 or 
${Q238}=16 or 
${Q239}=16 or 
${Q240}=16 or 
${Q241}=16 or 
${Q242}=16 or 
${Q243}=16 or 
${Q244}=16 or 
${Q245}=16 or 
${Q246}=16 or 
${Q247}=16 or 
${Q248}=16 or 
${Q249}=16 or 
${Q250}=16 or 
${Q251}=16 or 
${Q252}=16 or 
${Q253}=16 or 
${Q254}=16 or 
${Q255}=16 or 
${Q256}=16 or 
${Q257}=16 or 
${Q258}=16 or 
${Q259}=16 or 
${Q260}=16 or 
${Q261}=16 or 
${Q262}=16 or 
${Q263}=16 or 
${Q264}=16 or 
${Q265}=16 or 
${Q266}=16 or 
${Q267}=16 or 
${Q268}=16 or 
${Q269}=16 or 
${Q270}=16 or 
${Q271}=16 or 
${Q272}=16 or 
${Q273}=16 or 
${Q274}=16 or 
${Q275}=16 or 
${Q276}=16 or 
${Q277}=16 or 
${Q278}=16 or 
${Q279}=16 or 
${Q280}=16 or 
${Q281}=16 or 
${Q282}=16 or 
${Q283}=16 or 
${Q284}=16 or 
${Q285}=16 or 
${Q286}=16 or 
${Q287}=16 or 
${Q288}=16 or 
${Q289}=16 or 
${Q290}=16 or 
${Q291}=16 or 
${Q292}=16 or 
${Q293}=16 or 
${Q294}=16 or 
${Q295}=16 or 
${Q296}=16 or 
${Q297}=16 or 
${Q298}=16 or 
${Q299}=16 or 
${Q300}=16 or 
${Q301}=16 or 
${Q302}=16 or 
${Q303}=16 or 
${Q304}=16 or 
${Q305}=16 or 
${Q306}=16 or 
${Q307}=16 or 
${Q308}=16 or 
${Q309}=16 or 
${Q310}=16 or 
${Q311}=16 or 
${Q312}=16 or 
${Q313}=16 or 
${Q314}=16 or 
${Q315}=16 or 
${Q316}=16 or 
${Q317}=16 or 
${Q318}=16 or 
${Q319}=16 or 
${Q320}=16 or 
${Q321}=16 or 
${Q322}=16 or 
${Q323}=16 or 
${Q324}=16 or 
${Q325}=16 or 
${Q326}=16 or 
${Q327}=16 or 
${Q328}=16 or 
${Q329}=16 or 
${Q330}=16 or 
${Q331}=16 or 
${Q332}=16 or 
${Q333}=16 or 
${Q334}=16 or 
${Q335}=16 or 
${Q336}=16 or 
${Q337}=16 or 
${Q338}=16 or 
${Q339}=16 or 
${Q340}=16 or 
${Q341}=16 or 
${Q342}=16 or 
${Q343}=16 or 
${Q344}=16 or 
${Q345}=16 or 
${Q346}=16 or 
${Q347}=16 or 
${Q348}=16 or 
${Q349}=16 or 
${Q350}=16 or 
${Q351}=16 or 
${Q352}=16 or 
${Q353}=16 or 
${Q354}=16 or 
${Q355}=16 or 
${Q356}=16 or 
${Q357}=16 or 
${Q358}=16 or 
${Q359}=16 or 
${Q360}=16 or 
${Q361}=16 or 
${Q362}=16 or 
${Q363}=16 or 
${Q364}=16 or 
${Q365}=16 or 
${Q366}=16 or 
${Q367}=16 or 
${Q368}=16 or 
${Q369}=16 or 
${Q370}=16 or 
${Q371}=16 or 
${Q372}=16 or 
${Q373}=16 or 
${Q374}=16 or 
${Q375}=16 or 
${Q376}=16 or 
${Q377}=16 or 
${Q378}=16 or 
${Q379}=16 or 
${Q380}=16 or 
${Q381}=16 or 
${Q382}=16 or 
${Q383}=16 or 
${Q384}=16 or 
${Q385}=16 or 
${Q386}=16 or 
${Q387}=16 or 
${Q388}=16 or 
${Q389}=16 or 
${Q390}=16 or 
${Q391}=16 or 
${Q392}=16 or 
${Q393}=16 or 
${Q394}=16 or 
${Q395}=16 or 
${Q396}=16 or 
${Q397}=16 or 
${Q398}=16 or 
${Q399}=16 or 
${Q400}=16

If you would like additional functionality added to ODK's xlsform syntax, you could probably create a feature request by filing an issue here: https://github.com/opendatakit/xforms-spec

1 Like

If you put all your questions inside a group, say 'QUESTIONS', for example:

<QUESTIONS>
    <Q1>1</Q1>
    <Q2>16</Q2>
    <Q3></Q3>
    <Q4>3</Q4>
</QUESTIONS>

The following will 'search' every question (ie node) under QUESTIONS and return true if any one of them equals 16:

boolean(/QUESTIONS/*[.='16'])

The Power Of XPath! :frowning:

[of course, this is stepping outside the normal scope of XLSForms, but sometimes needs must... ]

@Xiphware is correct that adding wildcard support would make what he describes possible but it's not currently supported. So to be clear, a relevance condition like count(/data/QUESTIONS/*[.='16']) > 0 does NOT currently work in Collect although it's the right idea. If you'd like to do something like ask the same multiple choice question in a repeat and then see if any of those questions had an answer of "other", that is supported.

@Joseph_E_Flack_IV, it's tough but in general it's best to think outside of imperative bounds for writing forms! There's generally a way to do things with functions and filters although in this case wildcard support is missing.

If there's enough interest in wildcard support it's something that could be considered.

1 Like

Really!? Bugger... /data/QUESTIONS/*[.='16'] is standard XPath2, so I thought it would be OK. :frowning: [but to be honest I hadnt actually tried it, sorry]

Agreed. IMHO it would be better to expand the scope of XPath support, rather than introduce an entirely new, non-standard mechanism like for loops.

1 Like

As a consolation, perhaps this will make it a bit less painful in the mean time...

I'm assuming here you have a specified sequence of mandatory select_one questions, and soon as one is answered NONE you want to drop down to Q400. [corrrect me if I'm wrong]

Short answer: No - whichever way you cut-n-dice it, you'll end up having to enumerate the names of all 400 questions in some form, somewhere...

Firstly, in reality there isn't any 'skip' logic in XForms. Instead, there's show/hide logic - ie relevant="..." - that can be associated to any question, or group. Therefore, to 'skip' from Question X to Question Y (eg at the end of the form), you must explicitly hide every question between X and Y, either with a relevant="..." on each individual question, or by putting some/all the intervening questions in a group and putting a relevant="..." on that group.

Second, although you are creating your forms in a XLSForm spreadsheet, where table cell range operations like ${Q1:40} make sense, in actual deployment all these forms are converted to hierarchical XML. And in a hierarchy/tree there is really no concept of a 'range', but instead subtrees. Hence ${Q1:40} may make sense in an XLSForm spreadsheet, but in an actual XForm XML its meaningless/ambiguous.

Under my assumptions (sequential and mandatory) what you can do is for every question, have a fairly simple show/hide rule of the form:

Q2: relevant="coalesce(${Q1},'16') != '16' "
Q3: relevant="coalesce(${Q2},'16') != '16' "
Q4: relevant="coalesce(${Q3},'16') != '16' "
...

Basically, a question Q(x) is only shown if the previous question Q(x-1) has been answered, and you didnt select NONE-16. So as soon as you select 16 on a question, all subsequent ones cascade to become irrelevant. [this is basically just a slightly more abbreviated version of @Grzesiek2010's solution]

2 Likes

Thats awesome thank you @Grzesiek2010! I will let you know if I encounter any issues in moving forward with it!

Thank you very much @Xiphware for the detail explanation! I will try it out and let you know if anything challenging comes up

@LN @Xiphware That glob pattern / wildcard char syntax would indeed be awesome. Never seen it before but for some reason the syntax just looks intuitive.

1 Like

XPath is a bit like Welsh - it actually make some sense after you see it written down (and hear it), but until then you really cant predict how on earth to correctly write/spell it! :slight_smile:

(take my middle name for example... :wink: )