Placement of controls and models
XForms does not specify normatively where XForms controls and models must be placed within an HTML
document. The convention is to place
<xforms:model> elements within <xhtml:head>, and controls within
<xhtml:body>. Orbeon Forms is more flexible on this:
-
<xforms:model> can be placed within <xhtml:head> as is usual,
but also under <xhtml:body> and even nested within other XForms elements. For
example:
<xxforms:dialog id="my-dialog" model="my-dialog-model">
<xforms:label>My Dialog</xforms:label>
<xforms:group>
...
</xforms:group>
<xforms:model id="my-dialog-model">
<!-- Model used by the dialog <-->
...
</xforms:model>
</xxforms:dialog>
In this particular case, this allows you to write your dialog as a module in a completely
separate file and to XInclude that file within your main form.
At the moment, nested models behave exactly as if they were placed under
<xhtml:head>. It is just a syntactic convenience to be able to place them within
elements such as <xxforms:dialog>.
-
Attribute Value Templates (AVTs) can be placed on HTML elements outside
<xhtml:body>.
<xhtml:body lang="{instance('language')}">
...
</xhtml:body>
-
A single <xforms:output> control may be placed within
<xhtml:title>. This allows dynamically changing the HTML document title using XForms.
<xhtml:title>
<xforms:output value="instance('resources')/title"/>
</xhtml:title>
NOTE: Even though AVTs and <xforms:output> elements may be placed before any XForms
model, they are still considered part of the XForms "view" of the XForms document and refer to data placed in
models.
Handling of the model attributeIn XForms 1.1, the model linking attribute allows switching the XPath evaluation context from one model to another.
Consider the following example showing the Orbeon Forms behavior:
<!-- Define two models, m1 and m2 --> <xf:model id="m1">
<instance>I am i1</instance>
<instance>I am i2</instance>
<!-- Initially the default model is m1 -->
<!-- xxf:instance() allows accessing an instance in model m2 -->
<!-- NOTE: model="m2" could also be used with the same effect -->
<xxf:variable name="root-of-i2" select="xxf:instance('i2')"/>
<xf:group ref="$root-of-i2">
<!-- XPath focus points to instance in m2, but static context model is still m1 -->
<!-- Outputs "I am i2" because model attribute did not cause a model change -->
Orbeon Forms interprets this attribute fully statically: - XPath focus points to a node in instance i2 in model m2
- form author specifies
model="m1" - but statically, the context model is already m1 because that is the default
- therefore the implementation does not restore the XPath focus to the root element of i1 in model m1
- the XPath focus remains that of the enclosing group, which is the root element of instance i2 in model m2
xf:output displays "I am i2"
An implementation might instead choose to dynamically compare the context model within the group: - XPath focus points to a node in instance i2 in model m2
- form author specifies
model="m1" - implementation, at runtime, compares the two models and sees that they are different
- implementation therefore restores the XPath focus to the root element of i1 in model m1
xf:output displays "I am i1"
One benefit of the static Orbeon approach is that it makes static analysis of XPath expressions more likely to succeed.
To avoid confusion, we recommend using more explicit XPath expressions in such cases, for example:
<xf:output value="instance()"/>
<xf:output model="m1" value="instance()"/>
Another option is to use variables:
We also recommend overusing the ability to switch back and forth between models in a hierarchy of controls, as that tends to make the code harder to understand. Standalone label, hint, help and alert elements
In XForms, <label>, <hint>, <help> and
<alert> ("LHHA") elements must always be nested within a control. In HTML on the
other hand, the <label> element supports a for attribute which relates
the element to a control. Orbeon Forms follows HTML and support the for attribute on
all the LHHA elements. This allows placing LHHA elements in other locations on the page:
<table>
<tr>
<td>
<xforms:label for="first-name-control">Please enter your first name:</xforms:label>
</td>
<td>
<xforms:input id="first-name-control" ref="first-name" />
</td>
<td>
<xforms:hint for="first-name-control">Just your first name...</xforms:hint>
</td>
</tr>
</table>
<p>
<xforms:alert for="first-name-control">Oops the first name is not valid</xforms:alert>
</p>
NOTE: Standalone LHHA elements must not cross <xforms:repeat> boundaries.
Formatting
Rationale
It is usually recommended to use native XML types within XForms instances, as this guarantees
interoperability and maintainability. For example, a date of January 10, 2005 is stored in ISO
format as: 2005-10-01. However it is often necessary to format such values on screen
in a user-readable format, like "January 10, 2005", "10 janvier 2005", or "10. Januar 2005".
Orbeon Forms provides an extension attribute, xxforms:format, for that purpose.
xxforms:format must contain an XPath 2.0 expression. In your XPath expression you can
use all the XPath 2.0 functions, including those for date manipulation (external
documentation). However since XPath 2.0 functions don't provide any facility for date and time
formatting, you can in this attribute also use the following XSLT 2.0 functions:
The XPath expression is evaluated by the XForms engine whenever the value bound to the
xforms:input control changes and needs to be updated on screen. It is evaluated in the
context of the instance node bound to the control. This means that the current value of the control
can be accessed with ".". Often the value must be converted (for example to a date) in
which case the conversion can be done with a XPath 2.0 constructor such as xs:date(.)
or with as cast such as (. cast as xs:date?).
xforms:output
When using xforms:output, you can control the formatting of the date using the
xxforms:format extension attribute on the xforms:output control.
<xforms:output ref="date"
xxforms:format="format-date(xs:date(.), '[MNn] [D], [Y]', 'en', (), ())"/>
<xforms:output ref="size"
xxforms:format="format-number(., '###,##0')"/>
Default formatting
For both xforms:input and xforms:output, if the bound node is of one of
the following types: xs:date, xs:dateTime, xs:time,
xs:decimal, xs:integer, xs:float, and xs:double,
and if no xxforms:format attribute is present on the control, formatting is based on
properties. If the properties are missing, a built-in default
formatting is used. The default properties, as well as the built-in defaults, are as follows:
<property as="xs:string" name="oxf.xforms.format.date" value="if (. castable as xs:date) then format-date(xs:date(.), '[FNn] [MNn] [D], [Y]', 'en', (), ()) else ."/>
<property as="xs:string" name="oxf.xforms.format.dateTime" value="if (. castable as xs:dateTime) then format-dateTime(xs:dateTime(.), '[FNn] [MNn] [D], [Y] [H01]:[m01]:[s01] UTC', 'en', (), ()) else ."/>
<property as="xs:string" name="oxf.xforms.format.time" value="if (. castable as xs:time) then format-time(xs:time(.), '[H01]:[m01]:[s01] UTC', 'en', (), ()) else ."/>
<property as="xs:string" name="oxf.xforms.format.decimal" value="if (. castable as xs:decimal) then format-number(xs:decimal(.),'#,##0.00') else ."/>
<property as="xs:string" name="oxf.xforms.format.integer" value="if (. castable as xs:integer) then format-number(xs:integer(.),'#,##0') else ."/>
<property as="xs:string" name="oxf.xforms.format.float" value="if (. castable as xs:float) then format-number(xs:float(.),'#,##0.000') else ."/>
<property as="xs:string" name="oxf.xforms.format.double" value="if (. castable as xs:double) then format-number(xs:double(.),'#,##0.000') else ."/>
They produce results as follows:
-
2004-01-07 as xs:date is displayed as Wednesday January 7, 2004
-
2004-01-07T04:38:35.123 as xs:dateTime is displayed as Wednesday January 7, 2004 04:38:35 UTC
-
04:38:35.123 as xs:time is displayed as 04:38:35 UTC
-
123456.789 as xs:decimal is displayed as 123,456.79
-
123456.789 as xs:integer is displayed as 123,456
-
123456.789 as xs:float or xs:double is displayed as 123,456.789
NOTE: With the "if" condition in the XPath expressions, a value which cannot be converted to the appropriate type is simply displayed as is.
NOTE: For values of type xs:time or xs:dateTime, if you wish the time to be displayed using the current timezone instead of UTC, replace in the value attribute UTC by [ZN].
Iteration of XForms actions over sequences
Orbeon Forms supports the exforms:iterate attribute, also available as
xxforms:iterate attribute, on XForms action elements. Consider the following
instances:
<xforms:instance id="main-instance">
<instance xmlns=""/>
</xforms:instance>
<xforms:instance id="template-instance">
<book xmlns="">
<title/>
<author/>
</book>
</xforms:instance>
<xforms:instance id="source-instance">
<instance xmlns="">
<title>Don Quixote de la Mancha</title>
<author>Miguel de Cervantes Saavedra</author>
<title>Jacques le fataliste et son maître</title>
<author>Denis Diderot</author>
<title>Childhood's End</title>
<author>Arthur C. Clarke</author>
</instance>
</xforms:instance>
The following action iterates over the <title> elements of
source-instance. For each of those, a new <book> element, copied from
the template stored in template-instance, is inserted into main-instance.
Then values from the <title> and <author> elements are copied over
to the new structure. The XForms 1.1 context() function provides access to each of the
iterated nodes:
<xforms:action ev:event="xforms-ready"
xxforms:iterate="instance('source-instance')/title">
<xforms:insert context="instance('main-instance')" nodeset="book"
origin="instance('template-instance')"/>
<xforms:setvalue ref="instance('main-instance')/book[last()]/title"
value="context()"/>
<xforms:setvalue ref="instance('main-instance')/book[last()]/author"
value="context()/following-sibling::author"/>
</xforms:action>
The resulting main-instance is as follows:
<instance>
<book>
<title>Don Quixote de la Mancha</title>
<author>Miguel de Cervantes Saavedra</author>
</book>
<book>
<title>Jacques le fataliste et son maître</title>
<author>Denis Diderot</author>
</book>
<book>
<title>Childhood's End</title>
<author>Arthur C. Clarke</author>
</book>
</instance>
NOTE: Because Orbeon Forms uses XPath 2.0, xxforms:iterate is not limited to
returning node-sets, but can return sequences of items such as strings.
For more information about eXforms extensions, please visit the eXforms site.
Generalized context attribute
XForms 1.1 introduces the context attribute on <xforms:insert> and
<xforms:delete>. Orbeon Forms supports this convenient attribute on all XForms
elements changing the XPath evaluation context, including controls, actions, binds, and
submissions.
The context attribute overrides the in-scope XPath evaluation context for an action. It
applies before the ref and context attributes, but after the
model attribute.
One convenient use is to just change the context within a group:
<xforms:group context="personal-information">
...
</xforms:group>
NOTE: It is also possible to use ref in this case, but doing so has the side effect
of binding the group to an instance data node, which may affect group relevance, for example.
xxforms:download appearance on <xforms:output>
xxforms:group attribute on <xforms:select1> with appearance="full"
<xforms:select1> supports an extension attribute called xxforms:group
which allows grouping a series of radio buttons together in a way similar to the name
attribute in HTML.
In general, this attribute is not necessary. It is useful in the following case:
The xxforms:group attribute must contain an identifier unique between groups of radio
controls. Example:
<xforms:repeat nodeset="instance('countries')/country">
<xxforms:variable name="country" select="."/>
<xhtml:tr>
<xhtml:td>
<xforms:select1 appearance="full" ref="instance('selected')" xxforms:group="country-code-group">
<xforms:item>
<xforms:label/>
<xforms:value value="$country/us-code"/>
</xforms:item>
</xforms:select1>
</xhtml:td>
</xhtml:tr>
</xforms:repeat>
NOTE: This attribute does not work in noscript mode yet even though it would be very useful in this
case as well.
|