XForms was originally designed for handling forms on the web. Forms helped to kick off the web as an interactive medium and for ecommerce, with tasks such as searching, shopping, reading and writing email, editing documents online, configuring hardware, and banking.
XForms has been designed to improve the form-filling experience, and make production and management of forms easier. Issues addressed included authoring, reuse, internationalization, accessibility, usability, data structuring, client-side checking, device independence, support of common use cases and reduced reliance on scripting.
Properties of XForms include:
The original version of XForms was purely about forms, and followed HTML fairly strictly in what it could do in many cases. However, because of XForms' generality, it was quickly realised that it was capable of far more than only forms if certain parts were further generalised. And so was born XForms 1.1, that allowed not only forms to be created, but certain types of applications as well that you would not normally consider as being a form. XForms 2.0 continues this process of generalization.
Consider a simple form like this:
It is clear that we are asking for the method of payment being used, and if a credit card, its number and expiration date.
This can be represented in the XForms <model>
element,
which in XHTML would be contained within the <head>
element:
<model> <instance> <payment xmlns=""> <amount/> <method/> <number/> <expiry/> </payment> </instance> <submission action="http://example.com/submit" method="post"/> </model>
action
attribute.ref
attribute on the controls. This markup would appear within the
<body>
of an XHTML document:Please pay: <output ref="amount"/> <select1 ref="method"> <label>Payment Method</label> <item> <label>Cash</label> <value>cash</value> </item> <item> <label>Credit</label> <value>cc</value> </item> </select1> <input ref="number"> <label>Card Number</label> </input> <input ref="expiry"> <label>Expiration Date</label> </input> <submit> <label>Submit</label> </submit>
There are some things worth noting here:
The XForms Processor can directly submit the data collected as XML instance data. In the example, the submitted data might look like this:
<payment> <amount>99.00</amount> <method>cc</method> <number>1235467789012345</number> <expiry>2017-08</expiry> </payment>
but it is also possible to submit data in URL-encoded style, such as
http://example.com/submit?amount=99.00&method=cc&number=1235467789012345&expiry=2017-08
This is done by changing the submission
element to
<submission action="http://example.com/submit" method="get"/>
XForms processing keeps track of the state of the partially filled form through the instance data; this data can be initally empty as in the example above, or may be (partially) initialized with values, for instance:
<instance> <payment> <amount>99.99</amount> <method>cc</method> <number/> <expiry/> </payment> </instance>
Data may be also initialised from external sources. For instance, for forms that include a control to fill in a country, the data for the countries of the world can be obtained from an external resource:
<instance id="c" src="countries.xml"/>
If the countries data looks like this:
<countries xml:lang="en"> <country code="AF">Afghanistan</country> <country code="AX">Åland Islands</country> <country code="AL">Albania</country> <country code="DZ">Algeria</country> <country code="AS">American Samoa</country> ...
then a suitable select1
control could use this data as
follows:
<select1 ref="land"> <label>Country</label> <itemset ref="instance('c')/country"> <label ref="."/> <value ref="@code"/> </itemset> </select1>
This means that the country data is no longer hard-wired into forms, but can be sourced from a single file for the whole site, and is easily updated when necessary.
Binding expressions in XForms are based on XPath [XPath],
including the use of the @
character to refer to attributes, as
seen here.
XForms allows values to be calculated dynamically from the values in the model as they change.
For instance, if we add to the example above two values for the unit price of an item, and how many are being ordered:
<payment xmlns=""> <unitprice>99.99</unitprice> <howmany/> <amount/> <method/> <number/> <expiry/> </payment>
then we can add a calculation to calculate the total amount from these two:
<bind ref="amount" calculate="../unitprice * ../howmany" />
Whenever either of those two values is changed, the total amount is automatically updated.
XForms allows data to be checked for validity as the form is being filled. In the absence of specific information all values are returned as strings, but it is possible to assign types to values in the instance. For instance in the example, there are datatypes that represents an integer, and a decimal type for representing monetary values:
<bind ref="howmany" type="integer"/> <bind ref="amount" type="decimal"/>
but there is also a data type that represents a credit card, accepting between 14 and 18 digits:
<bind ref="number" type="card-number"/>
It is possible to add dynamic constraints to a value. For instance, if you want to restrict how many items are bought:
<bind ref="howmany" constraint=". < 10" />
which would prevent more than 9 items being ordered. There is also a function for checking that a credit card number is valid:
<bind ref="number" constraint="is-card-number(.)"/>
The data cannot be submitted until all constraints are met, and input controls bound to data not matching their constraints are typically marked specially (how they are marked is controllable by stylesheets). You can also include a message to be displayed should the constraints not be met:
<input ref="howmany"> <label>Number</label> <alert>Must be a whole number less than 10</alert> </input>
In the example, the input controls for number
and
expiry
are only relevant if the credit card option is chosen for
method
, but are required in that case. This is expressed as
follows:
<bind ref="number" type="card-number" relevant="../method='cc'" required="true()"/> <bind ref="expiry" relevant="../method='cc'" required="true()"/>
XForms processors have the option of graying out controls bound to non-relevant values, or of making them non-visible.
Putting it all together, the model would look like this:
<model> <instance> <payment xmlns=""> <unitprice>99.99</unitprice> <howmany/> <amount/> <method/> <number/> <expiry/> </payment> </instance> <bind ref="howmany" type="integer" constraint=". < 10"/> <bind ref="amount" type="decimal" calculate="../unitprice * ../howmany" /> <bind ref="number" type="card-number" relevant="../method='cc'" required="true()" constraint="is-card-number(.)"/> <bind ref="expiry" relevant="../method='cc'" required="true()"/> <submission action="http://example.com/submit" method="post"/> </model>
Although XForms has always had the ability to output values into the presentation of a form, a new feature of XForms 2.0 is the ability to output into attributes as well, with a feature known as attribute value templates, or for short, AVTs.
For instance, with
<output class="{if(total >= 0, 'positive', 'negative')}" ref="total"/>
the CSS style sheet can then have two rules, one for class
positive
, and one for negative
, for instance coloring
the output red if it is negative:
.positive {color: black} .negative {color: red}
When a single document contains multiple forms, each form needs a separate
model
element. The first model
element may omit a
unique id
attribute (as have all the examples above), but
subsequent model
elements require an id
attribute so
that they can be referenced from elsewhere.
In addition, form controls need to specify which model
element
contains the instance data to which they bind. This is accomplished through a
model
attribute alongside the ref
attribute. The
default for the model
attribute is the first model
element in document order.
The next example adds an opinion poll to the form.
<model> <instance> ...payment instance data... </instance> <submission action="http://example.com/submit" method="post"/> </model> <model id="poll"> <instance> <data xmlns=""> <helpful/> </data> </instance> <submission id="pollsubmit" action="..."/> </model>
Additionally, the following markup would appear in the body section of the document:
<select1 ref="helpful" model="poll"> <label>How useful is this page to you?</label> <item> <label>Not at all helpful</label> <value>0</value> </item> <item> <label>Barely helpful</label> <value>1</value> </item> <item> <label>Somewhat helpful</label> <value>2</value> </item> <item> <label>Very helpful</label> <value>3</value> </item> </select1> <submit submission="pollsubmit"> <label>Submit</label> </submit>
More XForms examples can be found in E Complete XForms Examples.