The author

XForms, an Introduction

Steven Pemberton, CWI, Amsterdam

About me

Researcher at the Dutch national research centre CWI (first European Internet site - 1988, whole of Europe connected to North America with 64kb link!).

Co-designed the programming language ABC, that was later used as the basis for Python.

In the late 80's designed and built a browser, with extensible markup, stylesheets, vector graphics, client-side scripting, etc. Ran on Mac, Unix, Atari ST.

Organised 2 workshops at the first Web conference in 1994, incuding one on Client-side Computing (this was before Javascript)

Co-author of HTML4, CSS, XHTML, XML Events, XForms, RDFa, etc

Chaired the W3C HTML WG for a decade. Still chair Forms WG

XForms

XForms, as the name suggests, was originally designed as a replacement for HTML Forms.

The first version did roughly that, but thanks to generality in the design we realised that with small changes it could do much more: you could use it for other applications as well.

The resultant design is XForms 1.1.

A new version XForms 2.0 is in preparation.

How can a Forms Standard be used for Applications?

XForms has input, output, and a processing engine. That's all you need for an application.

Although an application may not look like a form, all it is doing is taking some input from the user, and responding to it.

The Bottom Line

Experience with projects defined with XForms has shown:

Around a ten-times saving in costs, compared with traditional methods.

Shorter

Because (as you will see) you specify what you are trying to achieve and not how to achieve it, in XForms there is far less administration to worry about. This means: shorter programs.

How much shorter?

One correspondent who was converting a large collection of apps for a company from Javascript to XForms reported that the XForms were about ¼ the size.

Research has shown that development costs of software are dominated by debugging (90%). Other research has shown that the number of bugs in a program don't grow linearly with the size of the program, but the 1.5th power of the length of the program. So a program 10 times larger has 30 times as many bugs (and thus costs 30 times more to produce).

So that means we should expect the production time and cost to reduce to one eighth, about an order of magnitude. And indeed this seems to match experience.

Data point: 150 person years becomes 10!

A certain company makes BIG machines (walk in): user interface is very demanding — traditionally needed 5 years, 30 people.

With XForms this became: 1 year, 10 people.

Do the sums. Assume one person costs 100k a year. Then this has gone from a 15M cost to a 1M cost. They have saved 14 million! (And 4 years.)

Data point: A true story

Manager: I want you to come back to me in 2 days with estimates of how long it will take your teams to make the application

Two days later:

Programming man: I'll need 30 days to work out how long it will take to program it

XForms man: I've already made the application.

So, what is XForms

XForms, first released in 2002, is a markup language originally designed -- as the name suggests -- to update how forms are handled on the web.

The design was done by doing requirements analysis, and observation of how forms were being done on the web then, and trying to do it better.

Requirements

Obvious things that were needed included:

Initial experience

Particularly in the use of fixed strings rather than (potentially) calculated values for such things as the submission URI.

As a consequence this restricted what was possible with the language.

XForms 1.0 → 1.1

As a consequence, XForms 1.1 (2009) addressed these shortcomings, as well as adding a number of 'low-hanging fruits' which various implementations had added.

The resultant language turned out to be far more than a forms language, but a declarative application language.

Since XForms has input, output, and a processing engine, XForms is Turing-complete, and much more than just forms was now possible with the language.

And now XForms 2.0

XForms 2.0 is now in preparation. Based on experience with XForms 1.1, it has generalised even further.

XForms: the essence

There are two essential elements to XForms:

  1. Separation of data from controls
  2. Abstraction of controls

The Essence (1): Separation of Values from Controls

The first is to separate the data from the user interface. Separation of values from controls

Some advantages of the separation

You can see at a glance what data is being used and what is being returned

You can see much more clearly the relationships between differerent values

You can reuse models in different forms.

You can liken them to "data sheets" in the same way as CSS "style sheets".

The Essence (2): Intent-based Controls

The second part is that the controls, rather than expressing how they should look (radio buttons, menu, etc), express their intent ("this control selects one value from a list").

You then use styling to say how they should be represented, possibly with different styling for different devices (as a menu on a small screen, as radio buttons on a large screen).

These three controls are all identical (and bound to the same data), except they are presented differently. (All examples in these slides are live)

Source

Advantages of intent-based controls

In a similar way to the use of style sheets, particular choices of interaction are not hard-wired.

Device independence: you can use use different presentations on different devices

Accessibility: since the control states what it does, you can present a suitable alternative for accessibility use.

An Example

What this looks like: The model

<model>
   <instance>
      <data xmlns="">
         <firstname/>
         <secondname/>
      </data>
   </instance>
</model>

The body

<input incremental="true" ref="firstname">
   <label>First name:</label>
</input>
<input incremental="true" ref="secondname">
   <label>Second name:</label>
</input>
Your name is: 
   <output value="concat(firstname, ' ', secondname)"/>

Calculations

This calculates the increase of an exponential growth over a number of cycles.

Source

Calculations: The model

<instance>
   <data xmlns="">
      <init>1</init>
      <cycle>1.5</cycle>
      <start>1991</start>
      <end>2013</end>
   </data>
</instance>

Calculations: The body

<input incremental="true" ref="init">
   <label>Initial</label>
</input>
<input incremental="true" ref="cycle">
   <label>Cycle</label>
</input>
<input incremental="true" ref="start">
   <label>Start</label>
</input>
<input incremental="true" ref="end">
   <label>End</label>
</input>

Final: 
<output value="init * power(2, (end - start) div cycle)" />

Bind

Now to restrict the input to numbers:

<model>
   <instance>
      <data xmlns="">
         <init>1</init>
         <cycle>1.5</cycle>
         <start>1991</start>
         <end>2013</end>
      </data>
   </instance>
   <bind nodeset="init" type="double" />
   <bind nodeset="cycle" type="double"/>
   <bind nodeset="start" type="double"/>
   <bind nodeset="end" type="double"/>
/model>

Bind

In fact this can be expressed even shorter in this case:

<model>
   <instance>
      <data xmlns="">
         <init>1</init>
         <cycle>1.5</cycle>
         <start>1991</start>
         <end>2013</end>
      </data>
   </instance>
   <bind nodeset="*" type="double" />
/model>

This is because the nodeset attribute (and the ref attribute on input etc.) is an XPath expression. (XForms 1: XPath 1; XForms 2: XPath 2).

Example

Result

(Try typing a letter after one of the numbers; then hover over the indicator)

Source

Adding an error message

<input incremental="true" ref="init">
   <label>Initial</label>
   <alert>Must be a number</alert>
</input>

How this gets displayed depends on the implementation, and the use of style sheets.

XForms 2 detail

In XForms 1, a distinction was made between a single-node binding and a multiple-node binding. You used ref for one and nodeset for the other.

In XForms 2.0, this distinction is gone at the markup level: you use ref for both.

Moving the calculation to the model

<instance>
   <data xmlns="">
      <init>1</init>
      <cycle>1.5</cycle>
      <start>1991</start>
      <end>2013</end>
      <iterations/>
      <final/>
   </data>
</instance>
<bind nodeset="*" type="xf:double"/>
<bind nodeset="iterations" 
 calculate="(../end - ../start) div ../cycle"/>
<bind nodeset="final" 
 calculate="../init * power(2, ../iterations)"/>

In the body

Iterations: <output ref="iterations"/>
Final: <output ref="final"/>

XForms 2.0 detail

XForms 1 allowed only one bind per node, so you had to combine binds:

<bind nodeset="sum" type="integer" 
      calculate="../a + ../b" />

XForms 2 allows you to have several binds for one node, as long as they don't conflict.

Constraining values

<bind nodeset="end" 
      constraint=". &gt; ../start"/>

You can use an <alert> with this too:

<input incremental="true" ref="end">
   <label>End</label>
   <alert>Must be a number, and greater than 'start'</alert>
</input>

Constraining values

Try changing the End date to a year earlier than the Start.

Source

Moving the initial values out of the form

We have our initial data that looks like this:

<instance>
   <data xmlns="">
      <init>1</init>
      <cycle>1.5</cycle>
      <start>1991</start>
      <end>2013</end>
      <iterations/>
      <final/>
   </data>
</instance>

However, it is entirely possible to move that out of the form:

<instance src="data.xml"/>

and the data in a file:

   <data>
      <init>1</init>
      <cycle>1.5</cycle>
      <start>1991</start>
      <end>2013</end>
      <iterations/>
      <final/>
   </data>

External data

The source of the instance data may be anything addressable with a URL

<instance src="http://en.wikipedia.org/w/api.php?action=opensearch&amp;format=xml..."

XForms 1: data must be XML

XForms 2: data can be XML, JSON, CSV, and optionally other types, such as VCard. The data still looks like XML to the form.

Binds summary so far

So we have now seen types, calculations and constraints.

There are three other properties of data: relevant, readonly and required.

Required

You can make any value required, either conditionally or unconditionally. The indicators are added automatically by the system. Try "USA" as a country: you will see State becomes required:

Source

Required

<model>
   <instance>
      <data xmlns="">
         <name/>
         <country/>
         <state/>
      </data>
   </instance>
   <bind nodeset="name" required="true()"/>
   <bind nodeset="state"
         required="../country = 'USA'"/>
</model>

And in the body (nothing special here):

<input incremental="true" ref="name">
   <label>Name</label>
   <alert>May not be empty</alert>
</input>
<input incremental="true" ref="country">
   <label>Country</label>
</input>
<input incremental="true" ref="state">
   <label>State</label>
   <alert>May not be empty</alert>
</input>

Relevant

But in this case, the state isn't relevant for all countries.

So in this version we will say that the state is only relevant if the country is USA, and if relevant, always required. Again, try typing "USA" as the country:

Source

Relevant

<bind nodeset="name" required="true()"/>
<bind nodeset="state" required="true()" 
      relevant="../country = 'USA'"/>

Note that we have made no change to the body in this case. The control appears and disappears based purely on the relevance of the value.

Using stylesheets, you can also choose just to grey out non-relevant fields, rather than making them disappear.

Readonly

The final model-item property is readonly, which unsurprisingly conditionally makes a value read-only.

<bind nodeset="status" readonly="../role = 'beginner'" />

Countries

Of course you don't normally want people to enter their country textually, but by selecting. Here you use the <select> control:

<select1 class="select1" appearance="minimal" ref="country">
   <label>Country:</label>
    <item>
      <label>Belgium</label>
      <value>BE</value>
    </item>
    <item>
      <label>France</label>
      <value>FR</value>
    </item>
    <item>
      <label>Germany</label>
      <value>DE</value>
    </item>
 ...etc...
</select1>

"Appearance" is a hint to the implementation, and may have the values full, compact or minimal.

Countries

Source

Moving the selection data to the model

Especially in the countries case, it is better to have the data in one central place, even more so if there are several controls using the same data.

We can do that by creating an additional instance for the country data (you have some freedom here in the format). We'll keep it small here:

<instance id="countries">
  <countries xmlns="">
    <country code="BE">Belgium</country>
    <country code="FR">France</country>
    <country code="DE">Germany</country>
    <country code="NL">Netherlands</country>
    <country code="UK">United Kingdom</country>
    <country code="USA">United States of America</country>
  </countries>
</instance>

Selecting from model data

Then in the body:

<select1 ref="country">
  <label>Country</label>
  <itemset nodeset="instance('countries')/country">
    <label ref="."/>
    <value ref="@code"/>
  </itemset>
</select1>

Source

Even better

Of course, even better is to put the countries data in one place centrally, and then use.

<instance id="countries" src="countries.xml"/>

Then when a country changes its name, or a country disappears, or new one appears, you can change it once, and all your forms will be updated!

Using Data in the User Interface

Try changing the first field:

Source

Using data in the user interface

<instance id="default">
    <data xmlns="">                   
      <lang>Nederlands</lang>
      <name/>
      <age/>
      <gender/>
    </data>
</instance>

<instance id="q" src="labels.xml"/>

The labels

<questions>
  <set name="Nederlands">
    <language>Taal</language>
    <name>Naam</name>
    <age>Leeftijd</age>
    ...
  <set name="English">
    ...

In the body

<input ref="name">
   <label>
     <output
       ref="instance('q')/set[@name=instance('default')/lang]/name"/>
   </label>
</input>

Now you can just add a new set of labels for a new language to the labels file, and the form will update to the new language automatically.

Submission

Some forms/apps are perfectly standalone (for instance a form to calculate the date of Easter for a year.)

But of course you often need to submit data.

XForms allows you to submit any instance, serialized in a number of different ways, and then specify what should happen with the returned data. You have fairly fine-grain control over when data is submitted.

Submission

For instance

<model>
   <instance>
      <data xmlns="">
         <q/><n>10</n>
      </data>
   </instance>
   <submission action="http://example.com/search" method="get" />
</model>

and then:

<body>
   <input ref="q" label="Search"/>
   <submit label="Go"/>
</body>

Clicking on the submit button would cause the instance data to be submitted to the URL in the action attribute, with the data URL-encoded , eg:

http://example.com/search?q=test&n=10

The whole document would be replaced with the result.

Staying alive

However, an application normally wants to get the results and do something with it. To this end, the submission element has an attribute replace. Usually you want to put the results in a named instance, for which you use replace="instance"

<submission action="http://example.com/search" method="get"
   replace="instance" instance="results"/>

In XForms 1: returned data must in general be XML if it is to replace an instance

In XForms 2: also allowed JSON, CSV, and optionally other types.

Example

Suppose you want to preload an instance with some data, for instance an address, change the address, and then save it.

First step is to get the address:

<instance id="reference">
   <data xmlns="">
      <reference/>
   </data>
</instance>
<instance id="address"/>

Filling the address

<submission ref="instance('reference')"
    action="http://whatever"
    method="get" replace="instance"
    instance="address"/>

Then edit and post back

<submission ref="instance('address')"
     action="..."
     method="..."
     replace="none"/>

Event processing

Similar to the onclick style of processing, but generalised, XForms allows you to catch and respond to events. The whole of the XForms processing model has events that you can respond to. For instance

<setvalue ev:event="xforms-ready" 
          ref="state" value="0"/>

Which sets an instance value when XForms starts.

<setfocus ev:event="xforms-ready" 
    control="search"/>

which positions the focus on an initial control when XForms starts.

<send ev:event="xforms-value-changed"
      submission="submit1"/>

Which causes data to be submitted when the value bound to a control changes.

Example

Hiding and revealing interface elements

There is a control <switch> that allows you to switch between different interface elements:

<switch>
  <case id="init">
     ...
  </case>
  <case id="next">
     ...
  </case>
  ...
<switch>

You toggle between the different cases with a <toggle> action:

<toggle ev:event="..." case="next"/>

Switch

Source

XForms 2 switch

XForms 2 will add to this, by allowing the switch to be data-driven:

<switch caseref="state">
  ...

Example

Implementations

There are a number of ways you can implement XForms

A big advantage of server-side implementations is 'write once, run anywhere', since the server can sniff the device and deliver a version suitable for that device. Novell had a ground-breaking example of that.

Enterprise implementations

Many companies use XForms either internally or externally, and have their own implementations, either for internal use or for licensing. For instance:

Freely available implementations

Users

As you would expect with a new technology, first adopters are within companies and vertical industries that have control over the software environment used.

XForms 2.0

Very close to going to last call.

Already got (partial) implementations.

Hopefully ready next year.

Resources

Tutorial

Quick reference

Community Group

XForms 2.0 live version