Add XPath translate() function


(Dr. Gareth S. Bestor) #1

What is the general goal of the feature?
Add ability to perform character substitution, and removal, in a string; eg convert comma separated list to space separated: "1,2,345" --> "1 2 345".

What are some example use cases for this feature?
The existing string manipulation functions in ODK support searching for substrings (eg contains(), starts-with(), ends-with()), or extracting portions of a string (eg substr()), but do not readily allow reformatting the text in a string; for example changing a delimiter character. The XPath translate() function should be a useful addition to the suite of ODK string manipulation functions. For example, changing a comma delimited string list to a space, can enable the list to be susceptible to processing using selected-at(), selected(), and count-selected(). The translate() function also enables such things converting strings from lowercase to uppercase, by translate(${mystring}, 'abcde...', 'ABCDE...'), and removing specific characters from a string (by replacing them with nothing).

The translate() XPath function is well-defined and already supported by Enketo and libxml2. So this would bring javaRosa into better parity wrt other XForm/XPath processors.

What can you contribute to making this feature a reality?
I have already implemented and tested for javaRosa. I can open a PR if adding this new feature is approved.


(Martijn van de Rijdt) #2

I'm in favour of this native XPath 1.0 function. Thanks for this proposal!


(Dr. Gareth S. Bestor) #3

Finished code and unit test. PR opened.

Implements the XPath spec definition:

Function: string translate(string, string, string)

The translate function returns the first argument string with occurrences of characters in the second argument string replaced by the character at the corresponding position in the third argument string. For example, translate("bar","abc","ABC") returns the string BAr. If there is a character in the second argument string with no character at a corresponding position in the third argument string (because the second argument string is longer than the third argument string), then occurrences of that character in the first argument string are removed. For example, translate("--aaa--","abc-","ABC") returns "AAA". If a character occurs more than once in the second argument string, then the first occurrence determines the replacement character. If the third argument string is longer than the second argument string, then excess characters are ignored.

Tested using this simple form:

translate.xls (5.5 KB)
translate.xml (2.0 KB)

Note: Enketo already supports this XPath function so - if you can avoid Validate (eg KoboToolbox) - you can already try out this form with the new function under Enketo.


(Dr. Gareth S. Bestor) #4

Closing out this feature request as the javaRosa PR has been merged (thanks @ggalmazor). So this new XPath function should become available in a subsequent ODK Collect (and Validate) build. In the mean time it works presently under Enketo if you want to play around with the example forms.

I'll submit a corresponding PR to update the docs for this, and substring-before() and substring-after(), shortly.


(Dr. Gareth S. Bestor) #5