Introduction
The CommCare XForm specification is a subset of the far larger XForm 1.0 specification. It contains a few additional features not found in the XForm specification.
This specification continues to evolve. On the web you will often see references to JavaRosa and OpenRosa when the spec is discussed. OpenRosa was the name of the initial specification that formed the basis of this document. JavaRosa is a library that implements the XForm part of the OpenRosa specification.
The document assumes at least a fair understanding of XML and XPath. It is also useful to refer to XForms 1.0 for details about shared features.
Structure
The high-level form definition is structured as follows:
- model
- instance
- bindings
- body
The model contains the instance(s), the bindings and the actions. The first instance is the XML data structure of the record that is captured with the form. A binding describes an individual instance node and includes information such as datatype, skip logic, calculations, and more.
The body contains the information required to display a form.
Below is an example of a complete and valid XForm:
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:jr="http://openrosa.org/javarosa"
xmlns:orx="http://openrosa.org/xforms/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<h:head>
<h:title>My Survey</h:title>
<model>
<instance>
<data orx:version="2014083101" xmlns="http://openrosa.org/formdesigner/39A2CA97-2EB8-4A9C-A0D1-6AA666666A66">
<firstname></firstname>
<lastname></lastname>
<age></age>
<orx:meta>
<orx:instanceID/>
</orx:meta>
</data>
</instance>
<bind nodeset="/data/firstname" type="xsd:string" required="true()" />
<bind nodeset="/data/lastname" type="xsd:string" />
<bind nodeset="/data/age" type="xsd:int" />
</model>
</h:head>
<h:body>
<input ref="/data/firstname">
<label>What is your first name?</label>
</input>
<input ref="/data/lastname">
<label>What is your last name?</label>
</input>
<input ref="/data/age">
<label>What is your age?</label>
</input>
</h:body>
</h:html>
Outside of this simplified structure there are ways to define:
- form title as the
<title>
element, a child of the<head>
element, - linkages with external (mobile) applications,
- language dictionaries.
Instance
A <model>
can have multiple instances as childnodes. The first and required <instance>
is called the primary instance and represents the data structure of the record that will be created and submitted with the form. Additional instances are called secondary instances.
Primary Instance
The primary instance should contain a single childnode. In the example below <household>
will be populated with data and submitted. The primary instance’s single child is the document root that XPath expressions are evaluated on (e.g. in the instance below the value of /household/person/age
is 10).
<instance>
<household id="mysurvey" orx:version="2014083101">
<person>
<firstname/>
<lastname/>
<age>10</age>
</person>
<meta>
<instanceID/>
</meta>
</household>
</instance>
Any value inside a primary instance is considered a default value for that question. If that node has a corresponding input element that value will be displayed to the user when the question is rendered.
Nodes inside a primary instance can contain attributes. The client application normally retains the attribute when a record is submitted. There are 3 pre-defined instance attributes:
attribute | description |
---|---|
xmlns |
on the childnode of the primary instance: A unique namespace at which the form is identified by the server that publishes the Form and receives data submissions. [required] |
orx:version |
on the childnode of the primary instance in the http://openrosa.org/xforms/ namespace: Form version which can contain any string value. Like meta nodes this information is used as a processing cue for the server receiving the submission. |
name |
on the childnode of the primary instance: Form name (less-preferred alternative to the <title> element) |
jr:template |
on any repeat group node in the http://openrosa.org/javarosa namespace: This serves to define a default template for repeats and is useful if any of the leaf nodes inside a repeat contains a default value. It is not transmitted in the record and only affects the behavior of the form engine. For more details, see the repeats section. |
The primary instance also includes a special type of nodes for metadata inside the <meta>
block. See the Metadata section
There are 2 separate specs for primary instance nodes that describe cases and ledgers:
Secondary Instances - Internal
Secondary instances are used to pre-load read-only data inside a form. This data is searchable in XPath. At the moment the key use case is in designing so-called cascading selections where the available options of a multiple-choice question can be filtered based on an earlier answer.
A secondary instance should get a unique id
attribute on the <instance>
node. This allows apps to query the data (which is outside the root, ie. the primary instance, and would normally not be reachable). It uses the the instance('cities')/root/item[country='nl']
syntax to do this.
<instance>
<household id="mysurvey" version="2014083101">
<person>
<firstname/>
<lastname/>
<age>10</age>
</person>
<meta>
<instanceID/>
</meta>
</household>
</instance>
<instance id="cities">
<root>
<item>
<itextId>static_instance-cities-0</itextId>
<country>nl</country>
<name>ams</name>
</item>
<item>
<itextId>static_instance-cities-1</itextId>
<country>usa</country>
<name>den</name>
</item>
<item>
<itextId>static_instance-cities-2</itextId>
<country>usa</country>
<name>nyc</name>
</item>
<item>
<itextId>static_instance-cities-5</itextId>
<country>nl</country>
<name>dro</name>
</item>
</root>
</instance>
<instance id="neighborhoods">
<root>
<item>
<itextId>static_instance-neighborhoods-0</itextId>
<city>nyc</city>
<country>usa</country>
<name>bronx</name>
</item>
<item>
<itextId>static_instance-neighborhoods-3</itextId>
<city>ams</city>
<country>nl</country>
<name>wes</name>
</item>
<item>
<itextId>static_instance-neighborhoods-4</itextId>
<city>den</city>
<country>usa</country>
<name>goldentriangle</name>
</item>
<item>
<itextId>static_instance-neighborhoods-8</itextId>
<city>dro</city>
<country>nl</country>
<name>haven</name>
</item>
</root>
</instance>
Secondary Instances - External
The previous section discussed secondary instances with static read-only data that is present in the XForm document itself. Another type of secondary instances presents read-only data from an external source. The external source can be static or dynamic and is specified using the additional src
attribute with a URI value on an empty <instance>
node. Querying an external instance is done in exactly the same way as for an internal secondary instance.
<instance id="commcaresession" src="jr://instance/session"/>
See the section on URIs for acceptable URI formats that refer to an external secondary instance.
Bindings
A <bind>
element wires together a primary instance node and the presentation of the corresponding question to the user. It is used to describe the datatype and various kinds of logic related to the data. A bind can refer to any node in the primary instance including repeated nodes_. It may or may not have a corresponding presentation node in the body.
An instance node does not require a corresponding <bind>
node, regardless of whether it has a presentation node.
<bind nodeset="/d/my_intro" type="string" readonly="true()"/>
<bind nodeset="/d/text_widgets/my_string" type="string"/>
<bind nodeset="/d/text_widgets/my_long_text" type="string"/>
<bind nodeset="/d/number_widgets/my_int" type="int" constraint=". < 10" jr:constraintMsg="number must be less than 10" />
<bind nodeset="/d/number_widgets/my_decimal" type="decimal" constraint=". > 10.51 and . < 18.39" jr:constraintMsg="number must be between 10.51 and 18.39" />
<bind nodeset="/d/dt/my_date" type="date" constraint=". >= today()" jr:constraintMsg="only future dates allowed" />
<bind nodeset="/d/dt/my_time" type="time"/>
<bind nodeset="/d/dt/dateTime" type="dateTime"/>
<bind nodeset="/d/s/my_select" type="select" constraint="selected(., 'c') and selected(., 'd'))" jr:constraintMsg="option c and d cannot be selected together" />
<bind nodeset="/d/s/my_select1" type="select1"/>
<bind nodeset="/d/geo/my_geopoint" type="geopoint"/>
<bind nodeset="/d/media/my_image" type="binary"/>
<bind nodeset="/d/media/my_audio" type="binary"/>
<bind nodeset="/d/media/my_video" type="binary"/>
<bind nodeset="/d/media/my_barcode" type="barcode"/>
<bind nodeset="/d/display/my_trigger" required="true()"/>
Bind Attributes
The following attributes are supported on <bind>
nodes. Only the nodeset attribute is required.
attribute | description |
---|---|
nodeset |
Specifies the path to the instance node or attribute [required]. |
type |
Specifies the data type. These are discussed below. Considered “string” if omitted or if an unknown type is provided. |
readonly |
Specifies whether the user is allowed to enter data, using a boolean expression. Considered false() if omitted. enketo |
required |
Specifies whether the question requires a non-empty value, options: true() , and false() . Considered false() if omitted. |
relevant |
Specifies whether the question or group is relevant. The question or group will only be presented to the user when the XPath expression evaluates to true() . When false() the data node (and its descendants) are removed from the primary instance on submission. |
constraint |
Specifies acceptable answers for the specified prompt with an XPath expression. Will only be evaluated when the node is non-empty. |
calculate |
Calculates a node value with an XPath expression. |
jr:constraintMsg |
The message that will be displayed if the specified constraint is violated. |
Data Types
type | description |
---|---|
string |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
int |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
boolean |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
decimal |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
date |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
time |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
dateTime |
As in XML 1.0, optionally in “http://www.w3.org/2001/XMLSchema” namespace |
geopoint |
Space-separated list of valid latitude (decimal degrees), longitude (decimal degrees), altitude (decimal meters) and accuracy (decimal meters) |
binary |
String ID (with binary file attached to submission) |
barcode |
As string |
intent |
As string, used for external applications |
XPath Paths
XPath paths are used in XForms to reference instance nodes to store or retrieve data. Both absolute and relative paths are supported, along with using the proper relative path context node, depending on the situation. Paths can currently only reference XML elements (not attributes, comments, or raw text). The references .
and ..
are also supported at any point in the path.
The following are examples of valid paths:
.
..
/
node
/absolute/path/to/node
../relative/path/to/node
./relative/path/to/node
another/relative/path
//node
XPath Operators
All XPath 1.0 operators are supported, i.e. |
, and
, or
, mod
, div
, =
, !=
, <=
, <
, >=
, >
.
XPath Predicates
Predicates are fully supported but with the limitations described in XPath Axes and XPath Functions
XPath Axes
Only the parent, child and self axes are supported of the XPath 1.0 axes.
XPath Functions
A subset of XPath 1.0 functions, some functions of later versions of XPath, and a number of additional custom functions are supported. Some of the XPath 1.0 functions have been extended with additional functionality.
function | description |
---|---|
concat(* arg*) |
Deviates from XPath 1.0 in that it may contain 1 argument and that all arguments can be nodesets or strings. It concatenates all string values and all node values inside the provided nodesets. |
selected(string list, string value) |
Checks if value is equal to an item in a space-separated list (e.g. select data type values). |
selected-at(string list, int index) |
Returns the value of the item at the 0-based index of a space-separated list or empty string if the item does not exist (including for negative index and index 0). |
count-selected(string list) |
Returns the number of items in a space-separated list (e.g. select data type values). |
jr:itext(string arg) |
Obtains an itext value for the provided reference in the active language. enketo |
true() |
As in XPath 1.0. |
false() |
As in XPath 1.0. |
boolean(* arg) |
As in XPath 1.0. |
boolean-from-string(string arg) |
Returns true if arg is “true” or “1”, otherwise returns false. |
not(boolean arg) |
As in XPath 1.0. |
number(* arg) |
As in XPath 1.0. |
int(* arg) |
Converts to an integer. |
double(* arg) |
Converts to a floating-point number. |
string(* arg) |
As in XPath 1.0. |
format-date(date value, string format) |
Returns the date value formatted as defined by the format argument using the following identifiers:%Y : 4-digit year%y : 2-digit year%m 0-padded month%n numeric month%b short text month (Jan, Feb, etc)%d 0-padded day of month%e day of month%H 0-padded hour (24-hr time)%h hour (24-hr time)%M 0-padded minute%S 0-padded second%3 0-padded millisecond ticks%a short text day (Sun, Mon, etc) |
date (* value) |
Converts to date. |
regex(string value, string expression) |
Returns result of regex test on provided value. The regular expression is created from the provided expression string ('[0-9]+' becomes /[0-9]+/ ). |
coalesce(string arg1, string arg2) |
Returns first non-empty value of arg1 and arg2 or empty if both are empty and/or non-existent. |
join(string separator, nodeset nodes*) |
Joins the provided arguments using the provide separator between values. |
substr(string value, number start, number end?) |
Returns the substring beginning at the specified 0-based start index and extends to the character at end index - 1. |
string-length(string arg) |
Deviates from XPath 1.0 in that the argument is required. |
count(nodeset arg) |
As in XPath 1.0. |
sum(nodeset arg) |
As in XPath 1.0. |
max(nodeset arg*) |
As in XPath 2.0. enketo |
min(nodeset arg*) |
As in XPath 2.0. enketo |
round(number arg, number decimals?) |
Deviates from XPath 1.0 in that a second argument may be provided to specify the number of decimals. enketo |
pow(number value, number power) |
As in XPath 3.0. |
abs(number arg) |
As in XPath 3.0 enketo |
ceiling(number arg) |
As in XPath 1.0 |
floor(number arg) |
As in XPath 1.0 |
log(number arg) |
As in XPath 3.0 enketo |
log10(number arg) |
As in XPath 3.0 enketo |
upper-case(string arg) |
As in XPath 3.0 enketo |
contains(string arg) |
As in XPath 1.0 |
starts-with(string subj, string search) |
As in Xpath 1.0 |
ends-width(string subj, string search) |
As in XPath 3.0 enketo |
translate(string a, string b, string c) |
As in Xpath 1.0 |
replace(string input, string pattern, string replacement) |
As in XPath 3.0 enketo |
today() |
Returns today’s date without a time component. |
now() |
Returns the current datetime in the current time zone. |
random() |
Returns a random number between 0.0 (inclusive) and 1.0 (exclusive). |
depend(* arg*) |
Returns first argument. Shouldn’t need to be used. |
uuid(number?) |
Without arguments, it returns a random RFC 4122 version 4 compliant UUID. With an argument it returns a random GUID with the provided number of characters. |
checklist(number min, number max, string v*) |
Check wether the count of answers that evaluate to true (when it converts to a number > 0) is between the minimum and maximum inclusive. Min and max can be -1 to indicate not applicable. |
weighted-checklist(number min, number max, [string v, string w]*) |
Like checklist(), but the number of arguments has to be even. Each v argument is paired with a w argument that weights each v (true) count. The min and max refer to the weighted totals. |
position() |
As in XPath 1.0. |
instance(string id) |
Returns a secondary instance node with the provided id, e.g. instance('cities')/item/[country=/data/country] . It is the only way to refer to a node outside of the primary instance. Note that it doesn’t switch the XML Document (the primary instance) or document root for other expressions. E.g. /data/country still refers to the primary instance. |
current() |
In the same league as instance(ID) but always referring to the primary instance (and accepting no arguments). Unlike instance(ID), which always requires an absolute path, current() can be used with relative references (e.g. current()/. and current()/.. ). |
Metadata
This section describes metadata about the record that is created with the form. Metadata about the form itself (id, version, etc) is covered in the Primary Instance section.
The namespace of the meta block is either the default XForms namespace or "https://openrosa.org/xforms/"
.
<instance>
<data xmlns:jrm="http://dev.commcarehq.org/jr/xforms" xmlns="http://openrosa.org/formdesigner/C59FC6EE-2AD7-4DD5-892A-72DED4338CDE" uiVersion="1" version="637" name="Case Create">
<question2/>
<casename/>
<confirm/>
<orx:meta xmlns:cc="http://commcarehq.org/xforms">
<orx:deviceID/>
<orx:timeStart/>
<orx:timeEnd/>
<orx:username/>
<orx:userID/>
<orx:instanceID/>
</orx:meta>
</data>
</instance>
These meta elements have corresponding <bind>
elements with a calculation. Note that calculations may be recalculated, e.g. when a draft record is loaded. This could lead to undesirable results especially in case the result is a random value.
Another approach for adding meta data to a record is to use actions and external instances (e.g. a session instance).
The following meta elements are supported:
element | description | default datatype | default value | namespace |
---|---|---|---|---|
instanceID |
The unique ID of the record [required] | string | concatenation of ‘uuid:’ and uuid() | same as meta block |
timeStart |
A timestamp of when the form entry was started | datetime | now() | same as meta block |
timeEnd |
A timestamp of when the form entry ended | datetime | now() | same as meta block |
userID |
The username stored in the client, when available | string | same as meta block | |
deviceID |
Unique identifier of device. Guaranteed not to be blank but could be ‘not supported’. Either the cellular IMEI (with imei: prefix, e.g. imei:A0006F5E212), WiFi mac address (with mac: prefix, e.g mac:01:23:45:67:89:ab), Android ID (e.g. android_id:12011110), or another unique device ID for a webbased client (with domain prefix,e .g. enketo.org:SOMEID) | string | depends on client, prefixed | same as meta block |
deprecatedID |
The <instanceID/> of the submission for which this is a revision. This revision will have been given a newly generated <instanceID/> and this field is populated by the prior value. Server software can use this field to unify multiple revisions to a submission into a consolidated submission record. |
string | concatenation of ‘uuid:’ and uuid() | same as meta block |
Actions
The XForm can specify an action that should be taken in response to a particular event, as described in the XForms specification. The only actions supported are setvalue (XForms) and pollsensor (custom) which sets an instance value. They can be included by using <setvalue>
or <orx:pollsensor>
childnodes in the model (i.e. as siblings of <bind>
nodes).
The <setvalue>
action sets a value according to the expression or value provided. The <pollsensor
action has the “https://openrosa.org/xforms/” namespace, and is used to set geopoint value of the current location.
<!-- setvalue examples -->
<bind nodeset="/data/orx:meta/orx:timeStart" type="xsd:dateTime"/>
<bind nodeset="/data/orx:meta/orx:timeEnd" type="xsd:dateTime"/>
<setvalue event="xforms-ready" ref="/data/meta/timeStart" value="now()"/>
<setvalue event="xforms-revalidate" ref="/data/meta/timeEnd" value="now()"/>
<setvalue event="xforms-ready" ref="/data/meta/deviceID" value="instance('commcaresession')/session/context/deviceid"/>
<setvalue event="xforms-ready" ref="/data/meta/username" value="instance('commcaresession')/session/context/username"/>
<setvalue event="xforms-ready" ref="/data/meta/userID" value="instance('commcaresession')/session/context/userid"/>
<setvalue event="xforms-ready" ref="/data/meta/instanceID" value="uuid()"/>
<setvalue event="xforms-ready" ref="/data/meta/appVersion" value="instance('commcaresession')/session/context/appversion"/>
...
<!-- pollsensor example -->
<bind nodeset="/data/orx:meta/orx:location" type="geopoint"/>
<orx:pollsensor event="xforms-ready" ref="/data/meta/location"/>
An alternative syntax to set data values:
<bind nodeset="/data/meta/example" type="xsd:string"/>
<setvalue event="xforms-ready" ref="/data/meta/example"/>
some data
</setvalue>
Action Attributes
The following attributes are supported on action elements such as <setvalue>
.
attribute | description |
---|---|
ref |
Specifies the path to the instance node’ [required]. |
event |
Specifies the event that will trigger setting the value. See events supported [required] |
value |
Specifies the value to set. This could be a path or an expression (calculation). |
Action Events
The following event values are supported on action elements such as <setvalue>
.
event | description |
---|---|
xforms-ready | Occurs when the forms viewing application has finished the initial set up of all XForms constructs and is ready for user interaction. |
xforms-revalidate | Occurs when the viewing application validates all instance data in a particular model. This is the last event to occur before submitting (or saving a final record) and could be considered a ‘record-complete’ event. |
jr-insert | Occurs when a repeat element creates a new element. The evaluation context is that of the new element for that repeat. |
Cascade
The order in which form logic is evaluated and events are handled is of critical importance to ensure identical behaviour in different form engines.
Actions always fire before any bind logic is evaluated. So an xforms-ready event fires before relevants, calculates are evaluated.
Form logic specified in the <bind>
nodes is evaluated in the following order:
- relevant
- calculate
- required
- constraint
Body
The <body>
contains the information required to display a question to a user, including the type of prompt, the appearance of the prompt (widget), the labels, the hints and the choice options.
<h:body>
<input ref="/data/firstname">
<label>What is your first name?</label>
</input>
<input ref="/data/lastname">
<label>What is your last name?</label>
</input>
<input ref="/data/age">
<label>What is your age?</label>
</input>
</h:body>
Body Elements
The following form control elements are supported:
control | description |
---|---|
<input> |
Used to obtain user input for data types: string, integer, decimal, and date. |
<select1> |
Used to display a single-select list (data type: select1) |
<select> |
Used to display a multiple-select list (data type: select) |
<upload> |
Used for image, audio, and video capture |
<trigger> |
Used to obtain user confirmation (e.g. by displaying a single tickbox or button). Will add value “OK” to corresponding instance node when user confirms. If not confirmed the value remains empty. Behaviour can be modified to just show the label without a prompt, if appearance="minimal" is used (see appearances). The latter deviates from XForms and its use is discouraged. It is much better to use a readonly input for this purpose. |
The following user interface elements are supported:
element | description |
---|---|
<group> |
Child of <body> , another <group> , or a <repeat> that groups form controls together. See groups section for further details. |
<repeat> |
Child of <body> or <group> that can be repeated. See repeats for further details. |
Within the form controls the following elements can be used:
element | description |
---|---|
<label> |
Child of a form control element, <item> , <itemset> or <group> used to display a label. Only 1 <label> per form control is properly supported but can be used in multiple languages). |
<hint> |
Child of a form control element used to display a hint. Only 1 <hint> element per form control is properly supported but can be used in multiple languages). |
<help> |
Similar to <hint> to display a help message. enketo |
<output> |
Child of a <label> , <hint> or <help> element used to display an instance value, inline, as part of the label, hint, or help text. |
<item> |
Child of <select> or <select1> that defines an choice option. |
<itemset> |
Child of <select> or <select1> that defines a list of choice options to be obtained elsewhere (from a secondary instance). |
<value> |
Child of <item> or <itemset> that defines a choice value. |
Below is an example of a labels, an output, a hint, an itemset and value used together to define a form control:
<group ref="/data/loc">
<label>Location</label>
...
<select1 ref="/data/loc/city">
<label>City</label>
<hint>Cities in <output value="/data/loc/country"/></hint>
<itemset nodeset="instance('cities')/root/item[country= /data/loc/country ]">
<value ref="name"/>
<label ref="label"/>
</itemset>
</select1>
</group>
Body Attributes
The following attributes are supported on body elements. Note that most attributes can only be used on specific elements. If such a specific attribute is used on elements that do not support it, it will usually be silently ignored.
attribute | description |
---|---|
ref / nodeset |
To link a body element with its corresponding data node and binding, both nodeset and ref attributes can be used. The convention that is helpful is the one used in XLSForms: use nodeset="/some/path" for <repeat> and <itemset> elements and use ref="/some/path" for everything else. The ref attribute can also refer to an itext reference (see languages) |
appearance |
For all form control elements and groups to change their appearance. See appearances |
jr:count |
For the <repeat> element (see repeats). This is one of the ways to specify how many repeats should be created by default. |
jr:noAddRemove |
For the <repeat> element (see repeats). This indicates whether the user is allowed to add or remove repeats. Can have values true() and false() |
value |
For the <output> element to reference the node value to be displayed. |
rows |
Specifies the minimum number of rows a string <input> field gets. enketo |
Appearances
The appearance of the 5 form controls can be changed with appearance attributes. Appearance values usually relate to a specific data or question type. Multiple space-separated appearance values can be added to a form control.
An appearance attribute can also be used to indicate that an external app should be used as a form control.
The following appearances are supported:
appearance | description |
---|---|
field-list |
On a <group> this will show the complete group on one page. enketo |
minimal |
On a <select> and <select1> this will display the choice list as a “dropdown”. On a <trigger> this will show just the label, without a user prompt. enketo |
label |
On a <select> and <select1> this will only show the question labels without the radiobuttons or checkboxes. Together with field-list and list-nolabel this can be used to display a question table. |
list-nolabel |
On a <select> and <select1> this will only show the radiobuttons or checkboxes without labels. Together with field-list and label this can be used to display a question table. |
compact |
On a <select> and <select1> with image labels this will show just the image labels in a grid that can be selected by clicking on them. |
quick |
On a <select> and <select1> this will automatically advance to the next page when an answer has been selected. enketo |
intent:#### |
See External Applications |
Groups
A <group>
combines elements together. If it has a child <label>
element, the group is considered a presentation group and will be displayed as a visually distinct group.
A <group>
may or may not contain a ref
attribute. If it does, the group is considered a logical group. A logical group has a corresponding element in the primary instance and usually a corresponding <bind>
element. A logical group’s ref
is used as the context node for the relative ref
paths of its descendants.
A group can be both a logical and a presentation group.
Groups may be nested to provide different levels of structure.
Apart from providing structure, a logical group can also contain a relevant
attribute on its <bind>
element, offering a powerful way to keep form logic maintainable (see bind attributes).
The sample below includes both the body and corresponding instance. The respondent group is a logical group and the context group is both a logical and a presentation group. The context group will only be shown if both first name and last name are filled in.
<h:head>
<h:title>My Survey</h:title>
<model>
<instance>
<data id="mysurvey">
<respondent>
<firstname/>
<lastname/>
<age/>
</respondent>
<context>
<location/>
<township/>
<population/>
</context>
<meta>
<instanceID/>
</meta>
</data>
</instance>
....
<bind nodeset="/data/context"
relevant="string-length(../respondent/firstname) > 0 and
string-length(../respondent/lastname) > 0" />
....
</model>
</h:head>
<h:body>
<group ref="/data/respondent">
<input ref="firstname">
<label>What is your first name?</label>
</input>
<input ref="lastname">
<label>What is your last name?</label>
</input>
<input ref="age">
<label>What is your age?</label>
</input>
</group>
<group ref="/data/context">
<label>Context</label>
<input ref="location">
<label>Record the location</label>
</input>
<input ref="township">
<label>What is the name of the township</label>
</input>
<input ref="population">
<label>What is the estimated population size</label>
</input>
</group>
</h:body>
Repeats
Repeats are sections that may be repeated in a form. They could consist of a single question or multiple questions. It is recommended to wrap a <repeat>
inside a <group>
though strictly speaking not required.
A <repeat>
uses the nodeset attribute to identify which instance node (and its children) can be repeated.
A <repeat>
cannnot have a label child element. To display a label it should be wrapped inside a <group>
as shown below:
...
<h:head>
<h:title>A Survey with repeats</h:title>
<model>
<instance>
<data id="repeats" version="2014083101">
<person>
<name />
<relationship />
</person>
<meta>
<instanceID/>
</meta>
</data>
</instance>
...
</model>
</h:head>
<h:body>
<group ref="/data/person">
<label>Person</label>
<repeat nodeset="/data/person">
<input ref="/data/person/name">
<label>Enter name</label>
</input>
<input ref="/data/person/relationship">
<label>Enter relationship</label>
</input>
</repeat>
</group>
</h:body>
...
Creation, Removal of Repeats
The default behaviour of repeats is to let the user create or remove repeats using the the user interface. Commcare also asks the user whether the first repeat should be created. The user control for creating and removing repeats can be disabled by adding the attribute jr:noAddRemove="true()"
to the <repeat>
element.
There are 2 different ways to ensure that multiple repeats are automatically created when a form loads.
A. Multiple nodes can be defined in the primary instance of the XForm. E.g. see below for an instance that will automatically create 3 repeats for the above form.
...
<instance>
<data id="repeats" version="2014083101">
<person>
<name />
<relationship />
</person>
<person>
<name />
<relationship />
</person>
<person>
<name />
<relationship />
</person>
<meta>
<instanceID/>
</meta>
</data>
</instance>
...
B. Using the jr:count
attribute on the <repeat>
element. E.g. see below for the use of jr:count to automatically create 3 repeats for the above form. The value could also be a /path/to/node
and clients should evaluate the number of repeats dynamically (Note: It is problematic to implement this in a truly dynamic fashion, i.e. when the value changes, to update the number of repeats).
...
<h:body>
<group ref="/data/person">
<label>Person</label>
<repeat nodeset="/data/person" jr:count="3">
<input ref="/data/person/name">
<label>Enter name</label>
</input>
<input ref="/data/person/relationship">
<label>Enter relationship</label>
</input>
</repeat>
</group>
</h:body>
...
Default Values in Repeats
There are three different ways to provide default values to elements inside repeats.
A. Specify the values inside a repeat group with a jr:template=""
attribute in the primary instance. Any new repeat that does not yet exist in the primary instance will get these default values. The repeat group with the jr:template
attribute is not part of the record itself. So in the example below is for a form in which only a single repeat was created for John.
...
<instance>
<data id="repeats" version="2014083101">
<person jr:template="" >
<name />
<relationship>spouse</relationship>
</person>
<person>
<name>John</name>
<relationship>father</relationship>
</person>
<meta>
<instanceID/>
</meta>
</data>
</instance>
...
B. Specify the values for each repeat instance individually in the primary instance. In the example below the form will be loaded with 2 repeats with the values for John and Kofi.
...
<instance>
<data id="repeats" version="2014083101">
<person>
<name>John</name>
<relationship>father</relationship>
</person>
<person>
<name>Kofi</name>
<relationship>brother</relationship>
</person>
<meta>
<instanceID/>
</meta>
</data>
</instance>
...
C. Use the ‘jr-insert’ event and define a ‘setvalue’ action for it.
<setvalue event="jr-insert" ref="/data/repeat/name" value="'John'"/>
See the actions section for more details.
A Big Deviation with XForms
In XForms, relative XPaths should be evaluated relative to context, and absolute paths (/data/path/to/repeat) should be evaluated as absolute paths without considering context. If there are multiple repeats, the XPath /data/path/to/repeat would either return the first repeat (if e.g. a string value is requested), or all repeats (if a nodeset is requested).
However, in this spec, due to an unfortunate persistent historical error, absolute paths inside repeats are always evaluated as if they are relative to the current nodeset. In other words, the absolute XPath /data/path/to/repeat/node
when it is referred to from inside a repeat is evaluated as if it is the relative XPath ../node
.
In order to rectify this error at some time in the future, it would be very helpful if any form builders around this spec start generating relative references automatically.
External Applications
A form may include links to external applications that can be used to set instance values. This is done by calling out an intent on the Operating System and receiving a structured response review from the activity that handles that intent. This is described by an <intent>
element that is a child of the <head>
element.
This functionality includes the ability to pass parameters as part of the external application request. An encryption key may be passed to ensure that data is not stored unencrypted in the filesystem.
The example below shows a form that calls 2 different external apps to obtain values for 2 questions.
...
<h:head>
<h:title>...</h:title>
<model>
<instance>
<data xmlns:jrm="http://dev.commcarehq.org/jr/xforms" xmlns="http://openrosa.org/formdesigner/72AE4C2A-D6C3-4038-B128-C2AA7EFAF014" uiVersion="1" version="603" name="External Callouts">
<breath_count/>
<smsCallout/>
....
</data>
</instance>
</model>
...
<bind nodeset="/data/breath_count" type="intent" />
<bind nodeset="/data/smsCallout" type="intent" />
<odkx:intent
xmlns:odkx="http://opendatakit.org/xforms"
id="breath_count" class="org.commcare.respiratory.BREATHCOUNT">
<extra key="display_text" ref="data/text_Entry" />
</odkx:intent>
<odkx:intent
xmlns:odkx="http://opendatakit.org/xforms"
id="smsCallout"
type="vnd.android-dir/mms-sms"
class="android.intent.action.VIEW"
button-label="Send SMS">
<extra key="sms_body" ref="/data/content" />
<extra xmlns="http://www.w3.org/2002/xforms" key="address" ref="/data/address" />
</odkx:intent>
</h:head>
<h:body>
<input ref="/data/breath_count" appearance="intent:breath_count">
<label ref="jr:itext('breath_count-label')" />
</input>
<input ref="/data/smsCallout" appearance="intent:smsCallout">
<label ref="jr:itext('smsCallout-label')" />
</input>
</h:body>
...
Declaring external application
The <intent>
element (namespace: “http://opendatakit.org/xforms”) can be used to define the link with an external application. It supports the following possible attributes:
attribute | description |
---|---|
id | The id of the intent. Will be referenced by form elements [required]. |
class | The Android action which will be used in the intent [required]. |
type | The MIME type of the expected data. |
button-label | The button label text to show in the form UI |
The <intent>
may contain multiple <extra>
child elements that specify parameters to be passed to the intent target according to this bundle format review). These elements support the following attributes:
attribute | description |
---|---|
key | The string key for an extra value which will be included in the intent bundle [required]. |
ref | An XPath reference to a string value. |
key_aes_storage | (key name?, attribute on intent?, attribute on extra?): A raw AES symetric key. If any file references are returned from this callout, they should be encrypted by this key. review |
Using external application
As the code snippet above shows, the external application can be called by using an appearance on a form control, e.g.
<input ref="/data/breath_count" appearance="intent:breath_count">
The value after intent:
refers to the id
of an <intent>
element, in the example’s case to an intent with id breath_count
The corresponding <bind>
element has the datatype intent
.
Response
The response format expected from the external application is described here review.
Languages
Multi-lingual content for labels, and hints is supported. This is optional and can be done by replacing all language-dependent strings with ‘text identifiers’, which act as indexes into a multi-lingual dictionary in the model. The language strings can be identified with the jr:itext()
XPath function.
In the <model>
, a multi-lingual dictionary has the following structure:
<itext>
<translation lang="[language ISO 639 code]" default="true()">
<text id="[text id]">
<value>[translation of text with [text id]]</value>
</text>
</translation>
</itext>
Additional <text>
entries are added for each localizable string. The <translation>
block is duplicated for each supported language. The content should be the same (same set of text ids) but with all strings translated to the new language. It is recommended to use the ISO 639-1 (or else ISO 629-2 code) for the lang attribute value. The app should try to convert this to a human-readable language name to show in the UI. A default=”” attribute can be added to a <translation>
to make it the default language, otherwise the first listed is used as the default.
Every place localized content is used (all <label>
s and <hint>
s) must use a converted notation to reference the dictionary:
For example:
<label>How old are you?</label>
is changed to:
<label ref="jr:itext('how-old')" />
With the corresponding entries in <itext>
:
<translation lang="English">
...
<text id="how-old">
<value>How old are you?</value>
</text>
...
</translation>
<translation lang="Spanish">
...
<text id="how-old">
<value>¿Cuantos años tienes?</value>
</text>
...
</translation>
...
Not every string must be localized. It is acceptable to intermix <label>
s of both forms. Those which do not reference the dictionary will always show the same content, regardless of language.
It is even allowed to intermix both a ref
and a regular value. In this case, if the itext engine is missing it will refer to the regular value. E.g.
enketo
<label ref="jr:itext('mykey')">a default value</label>
In general, all text ids must be replicated across all languages. It is sometimes only a parser warning if you do not, but it will likely lead to headaches. Even within a single language, it is helpful to have multiple ‘forms’ of the same string. For example, a verbose phrasing used as the caption when answering a question, but a short, terse phrasing when that question is shown in the form summary. This can be done as follows:
<text id="how-old">
<value form="long">How old are you?</value>
<value form="short">Age</value>
</text>
There are three form attribute options for text strings:
text type | form attribute |
---|---|
single version | no form attr |
short version | short |
The different forms
are only supported for question captions (<label>
s inside user controls). The media section describes how to add non-text form labels in a similar manner.
Media
The <itext>
method described in the languages section can also be used for media labels. Media labels can be used in addition to text labels or instead of text labels.
....
<itext>
<translation default=true() lang="English">
<text id="/widgets/select_widgets/grid_test/b:label">
<value form="image">jr://images/b.jpg</value>
</text>
<text id="/widgets/display_widgets/text_media:label">
<value form="audio">jr://audio/goldeneagle.mp3</value>
<value>Listen to the sound of the Golden Eagle.</value>
</text>
</translation>
</itext>
...
Supported Media Types
The following table shows the supported media types, and their corresponding itext form
attribute values. The value of a media reference is a special URL similar to external secondary instances with prefixes or ‘connectors’ that will inform the client application where to download the resource.
media type | itext form attribute on <value> element |
---|---|
image | image and big-image |
audio | audio |
video | video |
By default, itext “image” values are not clickable. However, if you also include a “big-image”, the image displayed by “image” will be clickable and will display a pannable, zoomable view of the file specified by “big-image”. The user interface must provide a way to go back to the form after opening a “big-image”. Specifying “big-image” alone has no effect, you must always include “image”.
Files referenced by “image” and “big-image” may be the same; however, for performance reasons, it is recommended to create smaller thumbnail images to be referenced by “image”.
See the URI section for information about with URI formats are supported to refer to media.
URI Support
Throughout the XForm format URIs are used to refer to resources outside of the XForm itself. The jr
“protocol” is used to indicate the resource is available in a sandboxed environment the client is aware of. We can divide the supported URIs into two groups: binary and virtual.
Binary Endpoints
Binary endpoints point to files. The following are supported:
URI format | description |
---|---|
jr://images/path/to/file.png |
points to an image resource in the sandboxed environment |
jr://audio/path/to/file.mp3 |
points to an audio resource in the sandboxed environment |
jr://video/path/to/file.mp4 |
points to a video resource in the sandboxed environment |
Planned for the future:
jr://file/FILENAME.xml |
points to an XML resource in the sandboxed enviroment.enketo |
http://domain.com/path/to/file |
points to a publicly available resource on the web. review enketo |
Virtual Endpoints
These URIs refer to “virtual” documents that are available within the current client environment. Examples of URI variants that are supported across CommCare apps (though not in every app):
URI format | description |
---|---|
jr://instance/casedb |
points to all locally stored cases (see the CaseDb Specification) |
jr://instance/session |
points to the current session variables, aka metadata (see the Session Specification) |
jr://instance/fixture/FIXTUREID |
points to a fixture (see the Fixture Specification) |
jr://instance/ledgerdb |
points to a ledger (see the LedgerDb Specification) |