Wiki

Clone wiki

javarosa / buildxforms

XForms Training Materials

Learn how to build XForms for JavaRosa

Set up your computer to build and test XForms

Follow these instructions to install Notepad++, the sun wireless toolkit and the javarosa validator

Install Notepad++

For the first JavaRosa Xform training day, we used Notepad++ as the XML text editor. Here we've included the steps for installing it, though any text editor can be used for editing XForms

1. Install [http://notepad-plus.sourceforge.net/ Notepad++] on your machine 1. Install the XML Tools plugin from the [http://notepad-plus.sourceforge.net/uk/download.php Notepad++ download page]. Note that to install you will have to put all of the DLLs from the ext_lib directory in the Notepad++ directory (usually C:\Program Files\Notepad++), then copy the xml tools DLL to the plugins directory (C:\Program Files\Notepad++\plugins). 1. Once everything is installed, start up Notepad++. From the Plugins menu, there should be an option for XML Tools. We have found it useful to tick "Enable XML syntax auto-check" and "Tag auto-close". Also useful is using "Pretty print (XML only - with line breaks)". This will fix all of the indentation of your XML/XForm to make it more readable

Install the Sun WTK

1. If you haven't already, install a java runtime. This can either be the JDK or JRE. Chances are you have Java installed already, but if not and you're only planning on making XForms (not recompiling JavaRosa), head over to [http://www.java.com/getjava get java]. If you are planning to do core javarosa development, look at the [http://code.javarosa.org/wiki/GettingStarted Getting Started] for developers. 1. Install the [http://java.sun.com/products/sjwtoolkit/download.html Sun Java Wireless Toolkit for CLDC v 2.5.2]. It is recommended to install to the default location of C:\WTK2.5.2 to avoid having to re-map libraries locations.

JavaRosa XForm Validator

1. To avoid having instructions in multiple places, please follow the [http://code.javarosa.org/wiki/JavaRosa-XForm-Validator JavaRosa XForm Validator] setup instructions to both install and configure the validator software.

Reference material on XForms

What are XForms?

"XForms" is a format for creating forms/questionnaires in XML. XForms are similar to forms in HTML, and are meant to be the next-generation replacement for HTML forms. XForms are much more powerful than HTML forms.

An XForm is an XML document that describes your form, including what questions to ask (including the type of question and the question's caption or prompt), restrictions on the kinds of answers you can enter, and what you want your final data to look like. You author your XForm by hand in an XML editor.

XForms are read and filled out by an XForms client, which presents the questions to a user and lets them enter answers, much like you use a web browser to fill out HTML forms. The XForms client we have built and use is JavaRosa. XForms is a very complicated specification; JavaRosa only supports a simple subset of XForms, but this subset is getting more powerful all the time. JavaRosa also supports some customizations beyond the original XForms spec, specific to the needs of mobile users.

What is XML?

XML is a generic mark-up language for adding meaning to text. It is very similar to HTML, but is more generic and has stricter requirements. In fact, XHTML is an XML version of HTML. XML is simply tags that surround text and other tags. The types of the tags used and their hierarchy add meaning to a document. The tags you use can be named anything you want (this is the major different between HTML, which has a set of allowed tag names). A collection of tag names, along with rules about how they can be used and what they mean is called a schema. XForms is an XML schema. XHTML is another schema. In fact, the submitted data of your XForm is also an XML schema, different for every form.

XML Basics:

  • Tags can be self-closing (<tag />) or come in opening and closing pairs (<tag></tag>). Standalone tags like in HTML (a <br> that is never closed by a corresponding </br>) are not allowed.
  • Paired tags can have text or other tags inside them (<tag>some text <another-tag /></tag>). Which tags can appear inside other tags is determined by the schema.
  • Tags must be closed in the reverse order they were opened (<a><b></b></a>) (<a><b></a></b> is invalid XML)
  • The entire document must be enclosed within a single tag. This is called the top-level element
  • Tags can have attributes (<tag attribute="attribute value" another-attribute="value 2" />)
  • Certain special characters must be escaped when used in text or attribute values: < must be replaced with &lt;, > with &gt;, and & with &amp;

Tags can belong to a namespace, and multiple namespaces can be used within a single XML document. Namespaces let us use multiple XML schemas in a single document without conflicts, as two different schemas may use the same tag name. A namespace is simply an abbreviation (that we choose ourselves in our XML document) that is assigned to a given XML schema. For example, if we declare xf as our namespace for the XForms XML schema, XForms tags will look like <xf:input> and <xf:bind>. An XML document can have one default namespace, for which you don't need to use the namespace prefix in the tags for that schema. Typically, we make XForms our default namespace, as most of the tags in our document are XForms tags.

What is JavaRosa?

JavaRosa is an XForms client for mobile phones, written in J2ME. JavaRosa is an application platform that programmers can customize to suit different projects. There is no one 'JavaRosa application'. But at the heart of every JavaRosa application is the XForms engine, which is an activity that reads your XForms, presents the questions to a user and lets them enter answers, and saves or sends off the final data for your form.

JavaRosa is open source and is developed by members of the OpenRosa consortium around the world, with development teams in Tanzania, Kenya, South Africa, Uganda, Bangladesh, Pakistan, and USA.

Anatomy of an XForm

The skeleton of an XForm looks like this:

<h:html xmlns="http://www.w3.org/2002/xforms"
        xmlns:h="http://www.w3.org/1999/xhtml"
        xmlns:ev="http://www.w3.org/2001/xml-events"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:jr="http://openrosa.org/javarosa">
  <h:head>
    <h:title>[form title]</h:title>

    <model>
      <instance>
        [define the schema of your resulting data here]
      </instance>

      [define restrictions on your data (such as data types,
       range constraints, and skip logic) with bindings here]
      
    </model>
  </h:head>
  <h:body>

    [add controls that describe your questions here]

  </h:body>
</h:html>

The XForms schema is meant to be embedded in some other kind of XML schema, so note how our XForms tags are placed inside a skeleton HTML document. Also note our various namespace declarations at the top of the document, and how XForms is the default namespace. The XHTML namespace is given the prefix h. The namespace for JavaRosa customizations is given the prefix jr.

There are three main components to an xform:

1. The '''instance'''

The output of a filled-out XForm is itself another XML document. The schema of this XML document is custom to your XForm. You create a skeleton of this XML document and place it inside the <instance> tag. Questions refer to various parts of the instance and place their answers there as they are filled out. When your form is complete, the instance can be saved as a complete, self-contained XML document, and submitted from the phone to remote servers.

Since the instance must be a complete XML document on its own, and an XML document must contain one, and only one top-level element, the <instance> element must contain only one child element.

Sample instances:

<patient xmlns="http://commcare.org/patient-registration-0.1">
  <name />
  <sex />
  <age />
  <symptoms />
</patient>
<water-quality-survey xmlns="">
  <location />
  <well-id-number />
  <measurements>
    <ABT />
    <CC6 />
    <PSM />
  </measurements>
  <comments />
</water-quality-survey>

Once filled out, these instances may look like:

<patient xmlns="http://commcare.org/patient-registration-0.1">
  <name>DREW ROOS</name>
  <sex>male</sex>
  <age>25</age>
  <symptoms>cough fever rash</symptoms>
</patient>
<water-quality-survey xmlns="">
  <location>Mlandizi</location>
  <well-id-number>45</well-id-number>
  <measurements>
    <ABT>0.73</ABT>
    <CC6>4.32</CC6>
    <PSM>B</PSM>
  </measurements>
  <comments>QUALITY IS GOOD; WATER LEVEL LOW</comments>
</water-quality-survey>

Note how it's a good idea to make the tag names in your instance as descriptive as possible. Also note that since the top-level tag for your instance is the top-level element of an XML document, it should have an xmlns attribute, even if you leave it blank to start.

2. The '''bindings'''

Bindings let us attach restrictions to the type of data that may be entered into into the instance. The restrictions may be:

  • Data types, for example, indicating that a given question is meant to store dates, so only dates will be allowed as answers to that question. This may also affect how the question appears to the user (see 'controls'). Another kind of data type is restricting answers to numbers only.
  • Skip logic: only allowing a question to be answered if another question has a certain value (e.g., only asking 'is patient pregnant' if 'sex' is female)
  • Required: requiring that a question be answered before you can complete the form
  • Range constraints: limiting the kinds of answers that may be accepted (e.g., rejecting body temperatures over 50 and under 30)

Bindings are defined via a <bind> tag. The binding references a single tag in the instance via an XPath expression, and then defines the various restrictions on that question. Every question has it's own binding. Not every question needs a binding, though, such as if it uses the default data type (text) and has no other restrictions.

The instance and the bindings together comprise the XForm '''model'''.

3. The '''controls'''

The controls define the questions that the user actually sees. Each question presented to the user is its own control, and the user sees the questions in the same order listed in the XForm. A control is either an <input>, <select>, or <select1> tag. <input> is used for free-entry questions, such as text, numbers, and dates; <select1> is used for multiple-choice questions where you can pick only one choice; <select> is used for multiple-choice questions where you can pick many choices.

A control must define the following things:

  • Where in the instance the answer is stored (via an XPath expression)
  • The caption or prompt of a question
  • For multiple choice questions, the available choices and their captions

Note that most of the properties you associate with a question, such as whether it's required, the data type (text vs. numeric vs. date), and skip logic, are actually defined in the binding. The control and the binding have no direct knowledge about each other. The only thing that links a control and its binding is that they refer to the same destination tag in the instance.

What is XPath?

XPath is a mini-language for referring to nodes (tags) within an XML document. In XForms, we use XPath to address specific nodes/questions in the instance.

The basic format of an XPath path is /a/b/c, where a refers to the top-level element of the XML document (which must be named <a> in this example), b refers to the tag <b> that is an immediate child of <a>, and c refers to the tag <c> which is an immediate child of <b>. To use the sample instance above, /patient/name and /water-quality-survey/measurements/ABT are valid XPath paths.

XPath paths come in two varieties: absolute and relative. The paths above, and any path that starts with /, are absolute. This means to start searching for your node at the very top of the XML document.

If there is no beginning slash, the path is relative, which means you begin searching from some node (called the 'context node') that varies depending on the context where you're using the path. In most cases in an XForm, the context node of a relative path is simply the top-level element of the instance. This means that we could shorten the paths above to simply name (as /patient is assumed as the context node) and measurements/ABT (where /water-quality-survey is the context node).

The only exception is inside a binding when dealing with range constraints and skip logic. Here, the context node is the instance node that the binding refers to. There are two special kinds of relative paths that are useful in this situation:

  • . refers to the context node itself
  • .. refers to the parent tag of the context node We will see more examples of these as we cover constraints and skip logic.

There is also the more general concept of an 'XPath expression', in which you can do computations or comparisons on the values of nodes identified by paths. The details of XPath expressions are an advanced topic we won't cover here, but we use XPath expressions to define the conditions for constraints and skip logic, so you will see some examples there.

Basic controls

As said before, there are three basic XForms controls.

Use <input> for free-form questions such as text, number, or date. The format of the control is as follows:

<input ref="name">
  <label>What is your name?</label>
</input>

The value of the ref attribute is the path to the instance node where the answer to this question is stored. The content inside the <label> tag is the prompt presented to the user.

When the question is answered, the value that gets stored in the XML instance is the literal text or number that was entered, or for dates, the date formatted in XML date format (e.g., 2009-03-02).

Use <select> and <select1> for multiple choice questions (<select> for multi-select and <select1> for single-select). The format for both controls is identical:

<select ref="symptoms">
  <label>What are your symptoms?</label>

  <item>
    <label>Cough</label>
    <value>cough</value>
  </item>
  <item>
    <label>Rash</label>
    <value>rash</value>
  </item>
  <item>
    <label>Fever</label>
    <value>fever</value>
  </item>
  <item>
    <label>Itching and Peeling</label>
    <value>itch-peel</value>
  </item>
  <item>
    <label>Other</label>
    <value>other</value>
  </item>
</select>

ref and the first <label> are the same as for <input>. The difference is that now we define the choices as well. Each choice is defined in its own <item> tag. An <item> contains both a <label> and a <value>. Like <label> before, this defines the captions that the user will see for this choice. <value> defines an internal code for the choice that will be stored in the XML instance if this choice is selected. As such, it should be human-readable, but short and terse. For a multi-select, the <value>s of all selected choices will be stored in the instance, as a list separated by spaces. Clearly, <value> should not contain spaces! (or much punctuation at all, for that matter).

Bindings

The format of a binding is:

<bind nodeset="name" ... />

The nodeset attribute is just like ref for controls; it says which instance node this binding applies to. In addition to nodeset, the binding will contain one or more attributes to accomplish various goals, which we will now cover.

Data types

To restrict a question to a certain type, add the attribute type="[datatype]" to the binding, where [datatype] is string for text, int for integers, decimal for numbers with decimal points allowed, and date for dates. string is the default, so you don't need the type parameter for text questions or multiple-choice questions.

Required questions

To make a question required, add the attribute required="true()" to the binding (note the parenthesis).

Skip Logic

To make a question conditionally skipped based on the value of another question, we use the relevant attribute. We add this to the binding of the question that is conditionally skipped, not the question whose answer decides whether the other question is skipped. This is an important distinction that is confusing for many. For example, if we have a question A that decides whether questions B, C, and D are skipped, the bindings for B, C, and D will each have a relevant attribute that references the value of A.

The value of the relevant attribute is an XPath expression that references the values of previously-answered questions. If this expression evaluates to true, the question will be shown; if it evaluates to false, it will be skipped.

Here are some examples. Consider the following instance:

<patient>
  <name />
  <age />
  <sex />
  <pregnant />
  <in-school />
</patient>

<bind nodeset="pregnant" relevant="/patient/sex = 'f'" />
<bind nodeset="in-school" relevant="/patient/age &gt;= 4 and /patient/age &lt;= 25" />

....

<select1 ref="sex">
  <label>Sex of patient</label>
  <item><label>Male</label><value>m</value></item>
  <item><label>Female</label><value>f</value></item>
</select1>

In this example, the 'are you pregnant' question is only asked if the 'sex' question was answered 'female'. The 'are you in school' question is only asked if the patient is between 4 and 25 years old.

Important things to note:

  • The <= and >= comparisons for age had to be escaped into &lt;= and &gt;=
  • We only use absolute paths inside the relevant attribute; this is because the context node is now whichever node is specified in the nodeset attribute of the <bind>. Using relative paths like sex and age would no longer give us what we want!
  • When checking for a certain answer of a multiple-choice question, we compare against the <value> for that choice, as this is what is stored in the instance. Also, we compare it as a string, so we must enclose the literal value (f in this case) in single quotes.

Conditions like these can get quite complicated, so it's best at first to try to adapt from existing examples. If you have any further questions, ask one of the instructors. It is also important to fully test all possibilities when building your form to make sure your condition works as expected.

Range Constraints

To limit the range of acceptable values for a question, we use the constraint attribute. The value of the attribute is an XPath expression that is evaluated after the question is answered. The expression must evaluate to true for the answer to be accepted. If it evaluates to false, the user will be notified and forced to enter a different answer.

In order to be useful, the expression must actually reference the node to which the constraint (and the binding) applies. This is where the . relative path comes in useful, as it always refers to the node that the binding applies to (the node we are constraining).

Examples:

<bind nodeset="body-temperature" constraint=". &gt; 32 and . &lt; 45" />
<bind nodeset="birth-date" constraint=". &lt;= today()" />

If the value is outside of the allowed ranges, the constraint expression will be false, and the answer will be rejected.

By default, the user will receive a generic 'outside of allowed range' alert. You can change this to a custom alert by also adding the jr:constraintMsg parameter. For example:

<bind nodeset="birth-date" constraint=". &lt;= today()" jr:constraintMsg="Birthdates in the future are not allowed" />

Default values and Hidden questions

The XML instance is not required to be empty by default. The nodes in the instance may in fact contain data. This data will be used as default values for the questions.

Example:

<patient>
  <district>DAR ES SALAAM</district>
  <name />
  <sex />
  <age />
  <symptoms />
</patient>

DAR ES SALAAM will now be used as the default value for the 'district' question, but it may still be changed when the user answers the question. If they enter something different, the new answer will be written back to the instance, overwriting the default.

Default data in the instance must be validly formatted for the data type of the associated question. This means that for date questions, the date must be in YYYY-MM-DD format, and for multiple-choice questions, the data must correspond to the <value>s for that question's available choices. In general, the default value must be in the same format you would get if you had entered that value when answering the question itself. Failure to do so may cause your form to crash.

It is also possible to have default data in the instance, and no question control that actually references that data. This makes it impossible to change that data when filling out the form. This is how XForms does "hidden" questions (like you can do in HTML forms). This is useful for meta-data like form version – data that should change rarely throughout your deployment and that the user doesn't need to know about.

Submission

Traditional XForms (and HTML forms) let you describe how and where to submit the form as part of the XForm definition itself. The XForms spec itself supports this, however currently JavaRosa doesn't. In the JavaRosa platform, where, when, and how you submit your completed forms is defined through configuration settings at the application-level, not through any directives in the XForm itself. This will probably change in the future, with us supporting both methods.

Sample Forms

These forms illustrate the process of building an XForm. It starts with the most basic skeleton form with no questions, and gradually adds more capability with each revision.

  • Form 1: basic skeleton form with no questions; use this as the template for each form you create
  • Form 2: add 3 basic questions, including free-entry and multiple-choice
  • Form 3: add basic bindings and data types
  • Form 4: add default values
  • Form 5: add hidden fields
  • Form 6: add required questions
  • Form 7: add data constraints
  • Form 8: add skip logic

Updated