Introduction
XForms was originally designed as a new XML-based markup language for forms on the web, and version 1.0 [XF1] was just that. However, after initial experience, it was realised that the design had followed HTML too slavishly, in particular by only accepting static strings in places where expressions would be more useful. With some generalisation XForms became more powerful in the shape of XForms 1.1 [XF1]], and in the process became a Turing-complete language that could still do forms, but very much more as well. Rather than procedural or functional, XForms's programming model is declarative, where you define what you want to achieve rather than exactly how. This has proven to be very successful in reducing the time and costs of producing applications, typically by a factor of ten, over a wide range of different applications, both large and small.
XForms 2.0 [XF2] continues the process of generalisation, making the definition of applications even easier. We describe here some of the major differences.
XForms
The processing model of XForms is based on state: there is data, and a description of that data, such as types, constraints, and relationships between values. Initially the system ensures that the values are consistent with the description, and then goes into stasis until something changes, either from an action by the user, or internally from the system. Normally the system returns the system to stasis automatically, using an expression recalculation algorithm similar to how spreadsheets work, but the system also dispatches events to signal state change, which event listeners can respond to with actions, which in turn can cause further state changes.
Thus we split the description below into data and its descriptions and types, expressions, controls for user interaction, events, and actions. Finally submission is how XForms communicates with the outside world, talking to servers.
Data
Earlier version of XForms only accepted XML as a data format; XForms 2.0 extends this by defining mappings from external formats to an internal XML model, thus making those external formats appear as XML internally, but still round-tripped to the original formats. Mappings are currently defined for JSON and CSV, but it is possible for implementations to add other formats.
As an example, a JSON object such as
{"father": {"given": "Mark", "family": "Smith"}, "mother": {"given": "Mary", "family": "Smith"}}
would be transformed to the equivalent of the following:
<json type="object"> <father type="object"> <given>Mark</given> <family>Smith</family> </father> <mother type="object"> <given>Mary</given> <family>Smith</family> </mother> </json>
and a value would be selected with an XPath expression such as
mother/given.
An array such as
{"load": [0.31, 0.33, 0.32]}
is transformed to
<json type="object"> <load type="array"> <_ type="number">0.31</_> <_ type="number">0.33</_> <_ type="number">0.32</_> </load> </json>
and accessed with an expression such as load/_[1].
Data Properties
Model Item Properties (MIPs) are properties of data nodes within XForms:
type, constraints on the value, the relationship to other values, whether the
data is read-only or not, and under what conditions the data is relevant and
required. Originally a MIP for a data node had to be defined in one go in a
single bind
element. Now it may be extended over
several binds, with rules for how they are combined.
The new whitespace
MIP defines how whitespace is treated in
values when a user inputs a value: trimmed, compressed or removed entirely. For
instance, if the user inputs spaces when entering a credit card number, they
can be automatically and silently removed.
See also below on labels.
Types
There are a number of new types:
-
two IRI types: These allow the use of, and check the syntax of, 'international' web addresses and the likes, such as
https://zh.wikipedia.org/wiki/Wikipedia:关于中文维基百科/en
-
iemail type: allowing and checking 'international' email addresses such as
甲斐@黒川.日本
. Along with this, the existing 'legacy' email type has been improved: the original definition was rather loose; this has been tightened up to more closely match, and check, real-world email addresses. -
Telephone number type: allowing the checking of telephone numbers, such as +1 (234) 1234567
-
HTMLFragment type: this is a marker type that signals the intention of what the content represents, but doesn't check its validity. It exists primarily to allow rich-text editing controls to bind to values of such type.
The definition of validity has been slightly improved by allowing non-required values to be considered valid if empty. This simplifies the definition of controls for optional values. Consequently, the standard XForms datatypes no longer necessarily include empty as a possible value.
Expressions
XForms 2.0 uses XPath 2 [XP2], instead of XPath 1 [XP1]; this allows amongst other things atomic values and typed values; however, the expression language part of XForms 2.0 has been defined as a separate module allowing future versions of XForms easily to switch to newer versions of XPath [XP3].
Earlier versions of XForms only allowed data values to be injected into
element content of controls (using the output
control). With the
addition of Attribute Value Templates (AVTs), calculated values can now also be
injected into attributes, enabling the deprecation of many child elements.
For instance, where you previously had to say:
<output ref="maptile"> <mediatype value="site/type"/> </output>
you can now write:
<output ref="maptile" mediatype="{site/type}"/>
AVTs also create many new presentation options; for instance
class
values can now be calculated dynamically:
<output ref="balance" class="{if(. < 0, 'negative', 'positive')}"/>
Custom functions and variables have been added.
New functions are available:
-
bind(): returns the nodeset defined in a
bind
element, allowing expressions to be defined that work independently of how the data is structured. -
valid(), relevant(), readonly(), required(): give access to MIP values.
-
case(): for identifying which
case
of aswitch
has been selected. -
serialize(): serializes a value to a string in the same way a submission would work.
-
parse(): the complement of
serialize
- turns a string into an XML document element node, in the same way an external instance would be read. -
element(), attribute(): allows the construction of elements from values.
-
eval(), eval-in-context(): allows the evaluation of a string as an expression.
-
location-uri(), location-param(): functions to reveal how the XForm was called (i.e., with what URL).
-
uri-scheme(), uri-scheme-specific-part(), uri-authority(), uri-user-info(), uri-host(), uri-port(), uri-path(), uri-query(), uri-fragment(), uri-param-names(), uri-param-values(): helper functions for extracting parts of a URI. These can be used in initialising data values based on how the XForm was called.
Controls
Earlier versions of XForms distinguished whether a control expected a single
value, such as <input ref="height">
or a sequence of
values, such as <repeat nodeset="person">
. However, it was
observed that users did not benefit from this distinction, so the
nodeset
attribute has now been deprecated in favour of
ref
everywhere. If a control expects a single value, and gets a
sequence, it selects the first in the sequence (which is what also happened in
earlier versions).
Most controls have the helper elements label
,
hint
, help
, alert
as sub-elements. For
example:
<input ref="age"> <label>Age</label> <alert>Must be a non-negative whole number</alert> </input>
They may now alternatively be defined as attributes:
<input ref="age" label="Age" alert="Must be a non-negative whole number"/>
but also they may be attached to the node itself as a MIP, with a
bind
:
<bind ref="age" type="nonNegativeInteger" label="Age" alert="Must be a non-negative whole number"/> ... <input ref="age"/>
This has, amongst other things, the advantage of allowing the condition and matching message to be kept close to each other:
<bind ref="age" label="Age"> <bind type="integer" alert="Must be a whole number"/> <bind constraint=". >= 0 and . <= 120" alert="Must be between 0 and 120"/> </bind>
The label
elements and attributes are consequently now optional
on controls.
The semantics of how label
, help
,
hint
, and alert
work have been unified with the
output
control.
Previously if you wanted to know which iteration of a repeat was being
processed, there was a function index
to tell you. However, this
interacted poorly in combination with the XForms expression evaluation
algorithm, since a change to the index didn't initiate a recalculation. Repeat
controls now have an optional indexref
attribute which binds to an
instance value that is kept in sync with the repeat index, thus allowing
automatically updated calculations to take account of such values. Similarly
with switch
controls, which now have an optional
caseref
attribute. These attributes work bi-directionally: for
instance you can use caseref
to determine which case
has been selected, but also write to it to cause a particular case
to be selected. This means that actions such as <setindex/>
are now no longer needed (though are still available for backwards
compatibility).
The repeat and group elements now have an appearance='minimal'
attribute to turn them from block elements into inline elements. While this was
already possible with CSS definitions, this shorthand makes a frequently
occurring use case easier to define.
There is a new dialog
element for describing simple
dialogues.
Actions and Events
All actions now have an iterate
attribute to allow them to
iterate over a range of values:
<setvalue iterate="item[@selected=true()]" ref="." value=". + 1"/>
The XForms recalculation algorithm is described in four steps, and to match
this, in previous versions of XForms there were four actions: rebuild,
recalculate, revalidate, and refresh
; however, it turns out that all
most users want to ensure is that everything is up-to-date A new action
<update/>
subsumes the previous actions. The
update
action worries about the details.
It is now possible to call script (such as Javascript) from actions; this includes passing parameters.
In all versions of XForms the state of all instances is saved at start-up to
enable the reset
action. Now it is possible to define at which
point the instances are saved with the retain
action, and also to
reset one or more instances rather than all of them.
It is now possible to add properties to dispatched events. Event handlers are no longer disabled when their associated controls are disabled.
Submission
It is now possible to override the mediatype of an incoming document. This is useful for cases where the server uses the wrong, or a too-broad, mediatype, and for cases where the mediatype doesn't expose that the document is an application of XML.
The default submission method is get
(previously there was no
default).
A new submission attribute nonrelevant
replaces the existing
relevant
, adding new options (relevant
was a boolean,
but there are now more than two options for relevance processing).
Document Structure
XForms has always been designed to be integrated in another markup language,
whether XHTML, SVG, ODF, or whatever. To that end, XForms has not needed a root
element. However, for those occasions that an implementation needs a
free-standing usage of XForms, there is now an optional root element
<form>
.
Conclusion
Updating an existing language has the extra problem that you have to deal with legacy: you want to make changes without invalidating existing documents. This sometimes blocks the most obvious change, and demands creativity to find a suitable expression of the required functionality.
XForms 2.0 is a surprisingly expressive language. Declarative programming requires a different mindset, but once acquired allows the definition of apllications in an unexpectedly small number of lines of code. Examples include maps [Maps], multi-lingual applications and a presentation program [FC], and several games [Game1, Game2].
References
[XF1] Micah Dubinko, et al., (eds.), XForms 1.0, W3C, 2003, https://www.w3.org/TR/2003/REC-xforms-20031014/
[XF1]] John M. Boyer, (ed.), XForms 1.1, W3C, 2009, https://www.w3.org/TR/2009/REC-xforms-20091020/
[XF2] E. Bruchez, et al., (eds.), XForms 2.0, W3C, 2018, https://www.w3.org/community/xformsusers/wiki/XForms_2.0
[XP1] James Clark and Steve DeRose, (eds.), XML Path Language (XPath) 1.0, W3C, 1999, https://www.w3.org/TR/xpath10/
[XP2] Anders Berglund, et al., (eds.), XML Path Language (XPath) 2.0 (Second Edition), W3C, 2010, https://www.w3.org/TR/xpath20/
[XP3] Jonathan Robie, et al., (eds.), XML Path Language (XPath) 3.1, W3C, 2017, https://www.w3.org/TR/xpath-3/
[Maps] Steven Pemberton, XForms: an Unusual Worked Example, CWI, 2015, https://homepages.cwi.nl/~steven/Talks/2015/11-05-example/
[FC] Steven Pemberton, Form, and Content: Data-Driven Forms, XML Prague 2018 Conference Proceedings, pp 213-28, http://archive.xmlprague.cz/2018/files/xmlprague-2018-proceedings.pdf#page=225
[Game1] Steven Pemberton, A Game in XForms, CWI, 2017, https://homepages.cwi.nl/~steven/Talks/2017/06-10-iot/game-demo.html
[Game2] Steven Pemberton, Minesweeper in XForms, CWI, 2018, https://homepages.cwi.nl/~steven/Talks/2018/02-10-prague/minesweeper.xml