Relevance calculated: not working on enketo

Dear,

I have an issue which seems to appear only on enketo and not on ODK.

Relevance column can be calculated with question value but the relevance calculation cannot use calculate value
here an example, Q4 shows when Q1 &Q2 are answered but not Q3 nor the repeat group

test_repeat_appearance.xlsx (11.1 KB)

This is annoying for big form where a calculation can be used several time, duplicating it will impact performance and will make the form more difficult to maintain.

Is this a defect or did I missed something ?

Thanks in advance

Hi @delcroip,

Thanks for posting this. You've reached one of the less-intuitive parts of XPath. ODK Collect's behavior is actually incorrect and Enketo's behavior is correct here.

Your calculation is stored as <f_end>false</f_end> or <f_end>true</f_end>. The boolean value of these is both equal to true(). Here is some more information (see italic in intro): https://getodk.github.io/xforms-spec/#xpath-functions

So, in conclusion, it's best to stay away from boolean comparisons and compare strings instead (${f_end} = "false").

Cheers,
Martijn

Yup, this keeps catching me on occasion too...

Another alternative to explicitly comparing against the strings "true" and "false" [which always makes me feel like I need to take a bath afterwards...] is to instead always store boolean calculation results as a number - 0 or 1 - by surrounding your entire boolean expression with number(...).

That way the result will always get interpreted correctly if you happen to subsequently use it elsewhere in a calculation (eg relevance), and if it the value is submitted most backend systems will correctly interpret a 0 as FALSE and 1 as TRUE when mapped onto boolean datatype.

I don't think that's actually true in that case either, because boolean("0") is also true and the XPath evaluator has no knowledge of the datatype. See also here: https://codepen.io/MartijnR/pen/YJaBdQ (boolean(/data/c)) using a browser's built-in native XPath 1.0 evaluator.

So booleans are almost always surprising, when you obtain a value from another node.

1 Like

Thank you both @Xiphware and @martijnr

I will cast the boolean to number in the calculate then test their value against 1 and 0 hoping that it will be better performance wise. (I fell bad testing string value)

To cast to number, performance wise, do you think it is better to use the number() function or a simple if(cond,1,0) ?

Best regards

note: I have about 100 calculation in that form, I need to keep the perf in mind

Please note @martijnr comment is valid; there is indeed some ambiguity between evaluating boolean() against an intermediate calculation, vs a previously 'saved' calcualtion result (which is implemented as a so-called XPath nodeset operand). As defined, this can in fact produce a different outcome for the same value "0" (!)... [I report back as I dig around; I'm trying to determine what libxml2 does in this case...].

So your safest bet when dealing with saved boolean calculation results is, as @martijnr recommends, to perform an explicit string comparison.

In other situations - ie where the above is not this issue - I'd expect number() may be marginally faster than if(cond,1,0), simply because the latter requires two argument expression evaluations: the condition, plus whichever appropriate literal arg (which must still be evaluated as a XPath sub-expression), vs evaluating a single argument expression.

1 Like