Introduction

Changelog

The ODK XForms specification is used by tools in the Open Data Kit ecosystem. It is a subset of the far larger W3C XForms 1.0 specification and also contains a few additional features not found in the W3C XForms specification.

The purpose of this specification is to provide a common form description standard that many different kinds of compatible tools can be based on. Using a single, shared form description standard has the following advantages:

  1. Users in the ODK ecosystem can mix and match tools and reassess which they use based on their changing needs. In particular, they don’t get locked in to tools that may become deprecated or for which an attractive replacement becomes available.
  2. Tool implementors in the ODK ecosystem can benefit from feedback from a broad range of collaborators when designing new core functionality.
  3. Tool implementors in the ODK ecosystem can share core implementations.

This document is intended primarily for developers who build form processing engines or software form builders. Most organizations who use tools in the ODK ecosystem for data collection will prefer to create forms using the XLSForm standard or a graphical form builder.

A version of this specification was initially developed by the OpenRosa Consortium. JavaRosa is a Java library initially developed by the consortium as a J2ME app that implements this specification. There are now several other compatible implementations.

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) and the bindings. 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 id="mysurvey" orx:version="2014083101">
<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" />
<bind nodeset="/data/orx:meta/orx:instanceID" preload="uid" type="xsd:string"/>
</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:

Namespaces

XML namespaces provide a way to avoid name conflicts for element and attribute names. In ODK XForms, the elements and attributes that are also in XForms 1.0 are in the XForms namespace which is declared as the default namespace in the example above (xmlns="http://www.w3.org/2002/xforms"). Setting a default namespace means that non-prefixed elements and attributes are assigned that namespace.

Elements and attributes that are specific to ODK XForms and not defined by the XForms 1.0 specification should be separately namespaced. For historical reasons, the "http://openrosa.org/javarosa" namespace is used for many of these extensions. It is assigned the jr prefix in the example above and throughout this document.

For new additions, the "http://openrosa.org/xforms" namespace is preferred. It is assigned the orx prefix in this documentation.

For more information about namespaces, see the XML Namespaces specification.

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 is the first instance defined by the form and 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
id on the childnode of the primary instance: This is the unique ID at which the form is identified by the server that publishes the Form and receives data submissions. For more information see this Form List Specification. [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.
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

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="countries" src="jr://file/country-data.xml"/>

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=". &lt; 10" jr:constraintMsg="number must be less than 10" />
<bind nodeset="/d/number_widgets/my_decimal" type="decimal" constraint=". &gt; 10.51 and . &lt; 18.39" jr:constraintMsg="number must be between 10.51 and 18.39" />
<bind nodeset="/d/dt/my_date" type="date" constraint=". &gt;= 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/geo/my_geotrace" type="geotrace"/>
<bind nodeset="/d/geo/my_geoshape" type="geoshape"/>
<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.
required Specifies whether the question requires a non-empty value, using a boolean expression. 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.
saveIncomplete Specifies whether to automatically save the draft record when the user reaches this question, options true() and false(). Considered false() if omitted.
jr:requiredMsg Specifies the custom message to be displayed when the required is violated. Attribute in “http://openrosa.org/javarosa” namespace.
jr:constraintMsg Specifies the custom message to be displayed when the constraint is violated.
jr:preload Preloaders for predefined meta data. See preloaders.
jr:preloadParams Parameters used by jr:preload. See preloaders.

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)
geotrace Semi-colon-separated list of at least 2 geopoints, where the last geopoint’s latitude and longitude is not equal to the first
geoshape Semi-colon-separated list of at least 3 geopoints, where the last geopoint’s latitude and longitude is equal to the first
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(node node) Returns the number of items in a space-separated list (e.g. select data type values).
jr:choice-name(string value, node node) Returns the label value in the active language corresponding to the choice option with the given value of a select or select1 question for the given data node. (sorry)
jr:itext(string arg) Obtains an itext value for the provided reference in the active language.
indexed-repeat(nodeset arg, nodeset repeat1, int index1, [nodeset repeatN, int indexN]{0,2}) Returns a single node from a nodeset by selecting the 1-based index of a repeat nodeset that this node is a child of. It does this up to 3 repeat levels deep.
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.
decimal-date-time(dateTime value) Converts dateTime value to the number of days since January 1, 1970 UTC. This is the format used by Excel.
decimal-time(time value) Converts time value to a number representing a fractional day in the device’s timezone. For example, noon is 0.5 and 6pm is 0.75.
int(* arg) Converts to an integer.
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).*
* If form locale can be determined that locale will be used. If form locale cannot be determined the locale of the client will be used (e.g. the browser or app).
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.
contains(string haystack, string needle) As in XPath 1.0.
starts-with(string haystack, string needle) As in XPath 1.0.
ends-with(string haystack, string needle) As in XPath 3.0.
count(nodeset arg) As in XPath 1.0.
count-non-empty(nodeset arg) As in XForms 1.0.
sum(nodeset arg) As in XPath 1.0.
max(nodeset arg*) As in XPath 2.0.
min(nodeset arg*) As in XPath 2.0.
round(number arg, number decimals?) Deviates from XPath 1.0 in that a second argument may be provided to specify the number of decimals.
pow(number value, number power) As in XPath 3.0.
log(number arg) As in XPath 3.0.
log10(number arg) As in XPath 3.0.
abs(number arg) As in XPath 3.0.
sin(number arg) As in XPath 3.0.
cos(number arg) As in XPath 3.0.
tan(number arg) As in XPath 3.0.
asin(number arg) As in XPath 3.0.
acos(number arg) As in XPath 3.0.
atan(number arg) As in XPath 3.0.
atan2(number arg) As in XPath 3.0.
sqrt(number arg) As in XPath 3.0.
exp(number arg) As in XPath 3.0.
exp10(number arg) As in XPath 3.0.
pi() As in XPath 3.0.
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).
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(node arg?) Deviates from XPath 1.0 in that it accepts an argument. This argument has to be a single node. If an argument is provided the function returns the position of that node amongst its siblings (with the same node name).
property(string prop) Tbd
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()/..).
area(node-set ns | geoshape gs) Returns the calculated area in m2 of either a nodeset of geopoints or a geoshape value (not a combination of both) on Earth. It takes into account the circumference of the Earth around the Equator but does not take altitude into account.
once(* calc) The parameter will be evaluated and returned if the context nodes’s value is empty, otherwise the current value of the context node will be returned. The function is used e.g. to ensure that a random number is only generated once with once(random()).

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”. The latter is recommended.

<instance>
<data id="myform" orx:version="637">
<question2/>
<casename/>
<confirm/>
<orx:meta>
<orx:deviceID/>
<orx:timeStart/>
<orx:timeEnd/>
<orx:userID/>
<orx:instanceID/>
</orx:meta>
</data>
</instance>

These meta elements have corresponding <bind> elements with either a calculation or with preload attributes. Note that when using a calculation these values 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.

Using both a calculation and preload attributes is technically allowed but never recommended, because one will overwrite the other.

The following meta elements are supported:

element description default datatype 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 get 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   same as meta block
email The user’s email address when available. string   same as meta block
phoneNumber The phone number of the device, when available string   same as meta block
simSerial SIM serial number of phone, when available. string   same as meta block
subscriberID IMSI of phone prefixed (with imsi: prefix, e.g. imsi:SD655E212), when available. string   same as meta block

As mentioned in Bind Attributes, there are two different preload attributes. A particular combination of pre-load attributes populates a value according to a predetermined fixed formula, when a predetermined event occurs. Different combinations handle different events and use a different calculation.

Supported preload attribute combinations are:

jr:preload jr:preloadParams value event
uid   see instanceID xforms-ready if no existing value
timestamp start see timeEnd xforms-ready if no existing value
timestamp end see timeEnd xforms-revalidate
property deviceid see deviceID xforms-ready
property email see email xforms-ready
property username see userID xforms-ready
property phone number see phoneNumber xforms-ready
property simserial see simSerial xforms-ready
property subscriberid see subscriberID xforms-ready

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.
<range> Used to obtain numeric user input from a sequential range of values. As described here except that the incremental attribute is not included in this specification.

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).
<output> Child of a <label> or <hint> element used to display an instance value, inline, as part of the label, or hint 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 label, 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)
class Equivalent to class in HTML and allows a list of space-separate css classes as value. This attribute is only supported on the <h:body> element for form-wide style classes.
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()
autoplay For all 5 form control elements, this automatically plays a video or audio ‘label’ if the question is displayed on its own page, when the user reaches this page.
accuracyThreshold For <input> with type geopoint, geotrace, or geoshape this sets the auto-accept threshold in meters for geopoint captures. review
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.
mediatype For the <upload> element. The string value specifies the kind of media picker that will be displayed. Unlike in XForms 1.0, only one value can be specified. Possible values vary by client and examples include image/*, audio/* and video/*. Ignored if accept is also specified.
accept For the <upload> element. As from the XForms 2.0 wiki: “comma-separated list of suggested media types and file extensions used to determine the possible sources of data to upload.”
start For the <range> element. The lower bound of the range.
end For the <range> element. The upper bound of the range.
step For the <range> element. The increment between values that can be selected.

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. See the XLS Form specification for a list of appearance attributes that are available for each data type. Multiple space-separated appearance values can be added to a form control in any order.

An appearance attribute can also be used to indicate that an external app should be used as a form control.

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 behavior of repeats is to let the user create or remove repeats using the the user interface. 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 two 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>
...

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.

Events and Actions

XForm Events are dispatched following different steps in the form lifecycle. XForms Actions can be invoked in response to these events. This makes it possible to define exactly when certain tasks should occur.

Events

The following subset of events defined by the W3C XForms specification are supported:

event description
xforms-ready notification event dispatched after all form controls have been initialized.
xforms-value-changed notification event dispatched after an instance data node’s value changes.

Actions

The following subset of actions defined by the W3C XForms specification are supported:

action description
setvalue explicitly sets the value of the specified instance data node. See the W3C description. ref can be used in place of bind to specify a node path instead of a node id.

Action elements triggered by initialization events go in the model as siblings of bind nodes. Action elements triggered by control-specific events are nested in that control block.

Setting a dynamic value after form load

<bind nodeset="/data/now" type="dateTime"/>
<setvalue event="xforms-ready" ref="/data/now" value="now()" />

Setting a static value when a node’s value changes

<bind nodeset="/data/my_text" type="string" />
<bind nodeset="/data/my_text_changed" type="string" />
...
<input ref="/data/my_text">
<setvalue event="xforms-value-changed" ref="/data/my_text_changed">Value changed!</setvalue>
</input>

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 name]" 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. The language name in the lang attribute should be human-readable, as it is used to identify the language 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.

<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 two 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> element 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>You can add a sound recording.</value>
</text>
</translation>
</itext>
...

Supported Media Types

  • “image”
  • “audio”
  • “video”
  • “big-image”

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”.

URIs

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. At the moment only binary endpoints are supported.

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
jr://file/path/to/file.xml points to an XML resource in the sandboxed enviroment.

Encryption

Encrypted forms provide a mechanism to keep finalized data private even when using http: for communications (e.g., when SSL certificate is not there).It provides security for the duration in which the data is stored on a device and on the server.

Form Definition

Encrypted form definitions must have an explicit <submission/> element with the following attributes:

  • method: should always be set to form-data-post.
  • action: should be the url to which the submission should be posted; this is the server url.
  • base64RsaPublicKey:base64 encoding of an RSA public key. The corresponding private key will be needed to decrypt submissions.

The client generates a different symmetric encryption key for each finalized form and uses it to encrypt the submission and all media files. The base64RsaPublicKey is used to encrypt the symmetric key with the RSA/NONE/OAEPWithSHA256AndMGF1Padding algorithm.

Here is an excerpt used in an encrypted form:

<instance>
<sample id="sample-v1.0">
<orx:meta>
<orx:instanceID/>
</orx:meta>
<name/>
</sample>
</instance>
<submission method="form-data-post"
action="https://my-opendatakit.appspot.com/submission"
base64RsaPublicKey="MIIBIjANB...JCwIDAQAB" />

Future

See the outstanding issues list to get an idea of how this specification will evolve. Join the conversation!