1. What is the issue? Please be detailed.
Using regex to restrict a decimal number to precision of one doesn't work when the user uses 0 as the decimal number.
2. What steps can we take to reproduce this issue?
Create a decimal element in a XFORM with the constraint
((.>32 and .<45) and regex(.,'[0-9]+[.][0-9]')) or .=''
3. What have you tried to fix the issue?
tried:
((.>32 and .<45) and regex(.,'^\d+.[0-9]$')) or .=''
Also tried:
((.>32 and .<45) and regex(.,'^\d+.\d$')) or .=''
4. Upload any forms or screenshots you can share publicly below.
Welcome @magp18,
Which number/decimal exactly do you want to exclude around 0? As you use a mathematical and clause (together with the regex), numbers are only valid between 32.1 and 44.9.
Here are three solutions based on type text and examples that the string cast is the problem with type decimal. RegEx07.xlsx (20.2 KB)
Developed/tested using the ODK Online validator.
You may set required true (or yes).
It seems that the system treats decimal 32.0 and 32.00 as (integer) 32. Is this what we attend? Mathematically, yes, but probably not as its string representation?
You can add a calculate or decimal type variable to copy/store the ##.0 entry as real decimal. But there is no solution to keep the .0 digit, as you will still have the cast problem. Even if you enter 32.0 directly in a decimal field, after save you will see 32, without decimal digit. (32 and 32.0 are equal as decimal.)
If we find a way to get the decimal digits as number, a solution with type decimal could be possible. Maybe, @Xiphware or @yanokwa or the community has an idea, how to use type decimal and check for exactly one decimal digit? Unfortunately, the format-number() function is not available so far (https://www.w3.org/TR/xpath-functions-30/#func-format-number).
if the number is an integer, the number is represented in decimal form as a Number with no decimal point and no leading zeros, preceded by a minus sign (-) if the number is negative
otherwise, the number is represented in decimal form as a Number including a decimal point with at least one digit before the decimal point and at least one digit after the decimal point, preceded by a minus sign (-) if the number is negative; there must be no leading zeros before the decimal point apart possibly from the one required digit immediately before the decimal point; beyond the one required digit after the decimal point there must be as many, but only as many, more digits as are needed to uniquely distinguish the number from all other IEEE 754 numeric values.
Hi @Xiphware,
The more complicated case seems: 33.0 is valid, but 33 or 33. or 33.00 are invalid. And you want to use a decimal type UI (or at least to store a decimal copy) with exactly one decimal digit, permanently. format-number() would get the job, but seems not available yet.
Hmmm I see your point but should we treat 33.0 as 33 ? For mathematic calculations as you said, it does make sense since it will be seen as the same number, but for capture of data is a little bit misleading since 33.0 is more precise than 33
These are essentially all the same numbers (to XPath), so if you do need to distinguish between them then you are not going to be able to capture them using a decimal question, but must instead use a text type question, and treat them as char strings in your validation logic. That doesn't preclude you converting the string - either explicitly or implicitly - to a number to, say, perform < or > comparisons.
Note, at the end of the day, everything gets converted to a suitable string representation in the XML form payload that is sent up to your server. If you send up a decimal question response then the underlying XForm engine (Collect, Enketo, ...) is going to convert your (decimal) number to a string for this XML payload, and you dont have a lot of control over how (eg it could well drop a 'xxx.0' entirely...). If you want strict control over how your (decimal) numbers are represented, or validated, then you'll really need to capture and treat them as text (strings)