sample for odk forum.xlsx (13.6 KB)
Hello All,
Thanks for the immense support provided on this platform. I have a slight challenge. I'm trying to insert two different skip logics under the "relevant" column, for example, I have a question that asks about the type of building structure. Succeeding questions become relevant based on the option selected e.g either residential, collective or other. There is also a question that asks about permission from building owner. If the answer is "No" it is expected that it should go to the end of the questionnaire (that's not a problem). However, Other questions too are dependent on the type of building structure. So I want to combine the responses for building structure with the affirmative permission .i.e. the relevant building option with the 'Yes' permisiioon from the owner of the building. How do I go about this? I have attached a sample of the form. The section in question is the last section (dwelling) and the logic in question is in red.
Found a way around it
Can you share your approach so others could benefit?
I believe your existing relevant tests may be incorrect:
relevant="${str_type} = selected(${str_type},'str_res') or selected(${str_type},'str_coll') or selected(${str_type},'str_oth')"
because you appear to be comparing ${str_type}
- which is text - against a boolean selected(...)
expression...
Note, if you have a whole bunch of questions that are all dependent on a particular response, rather than having to put a relevant='...'
for each of them, it may be simpler to put all the dependent questions in a group, and then just have a single relevant='...'
for the group.
Ditto, I'm also curious as to what your solution/'way around' is?
Thanks for the assistance Dr. Bestor. Attached is a snippet of the form. Basically, I changed the logic to ensure that succeeding questions are dependent on permission being granted by the building owner. The permission question is only relevant based on a couple of responses.sample for odk forum.xlsx (13.6 KB)
NP. But your line 20 relevant expression for continue_1 is still not right:
${str_type} = selected(${str_type},'str_res') or selected(${str_type},'str_coll') or selected(${str_type},'str_oth')
This will if fact evaluate OK, and give you a true/false result, but its probably not going to be what you expect... If you compare a string (ie ${str_type}
) to a boolean (ie selected(...)
) then the XPath =
equals operator will first convert the string to a boolean (!) and then do a boolean compare, and my guess is you probably dont know if "str_res" will turn out to be true() or false(), eh?
You may be right. However, series of tests and pilots after I made the correction showed no issues. I will run it again to be sure.
Thanks.
Your original expression probably works, but that is more from 'a series of fortunate events', than design...
To explain, your original XPath expression:
${str_type} = selected(${str_type},'str_res') or selected(${str_type},'str_coll') or selected(${str_type},'str_oth')
will be evaluated according to XPath operator precedence (see here); ie shown with brackets it is equivalent to:
( ( (${str_type} = selected(${str_type},'str_res')) or selected(${str_type},'str_coll') ) or selected(${str_type},'str_oth') )
So the first subexpression evaluated is: ${str_type} = selected(${str_type},'str_res')
. This compares different data types - a string element against a boolean element - which XPath does by making both booleans; again, from the W3C spec:
If one object to be compared is a node-set and the other is a boolean, then the comparison will be true if and only if the result of performing the comparison on the boolean and on the result of converting the node-set to a boolean using the boolean function is true.
So the subexpression becomes: boolean(${str_type}) = selected(${str_type},'str_res')
Now, because your ${str_type} just so happens to come from a select-one, and is therefore (always) going to be a non-empty string, boolean(${str_type})
will basically always return 1. Again, from the W3C spec:
The boolean function converts its argument to a boolean as follows:
- a number is true if and only if it is neither positive or negative zero nor NaN
- a node-set is true if and only if it is non-empty
- a string is true if and only if its length is non-zero
Which is to say: 1 = selected(${str_type},'str_res')
And because an equality comparison between a boolean against 1 is basically redundant, your overall expression simplifies to:
selected(${str_type},'str_res') or selected(${str_type},'str_coll') or selected(${str_type},'str_oth')
Which is probably what you really meant to say in the first place, eh!
Sorry for the extremely long-winded explanation, but I think its important to fully understand how these XPath expressions will evaluate your inputs. If, for example, your ${str_type} came from a regular user text input, it could be blank (ie the user didnt enter anything), and your expression would basically become not(selected(${str_type},'str_res')) or selected(${str_type},'str_coll') or selected(${str_type},'str_oth')
, which may give an unanticipated result.