XForms - Other Extensions

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 attribute

In 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">
    <xf:instance id="i1">
        <instance>I am i1</instance>
    </xf:instance>
</xf:model>
<xf:model id="m2">
    <xf:instance id="i2">
        <instance>I am i2</instance>
    </xf:instance>
</xf:model>

<!-- 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 -->
    <xf:group model="m1">
        <!-- Outputs "I am i2" because model attribute did not cause a model change -->
        <xf:output value="."/>
    </xf:group>
</xf:group>

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:

<xf:output value="$i1"/>

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 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".

Default formatting

For xforms:output and for xforms:input in static readonly mode, if the bound node is of one of the following types: xs:datexs:dateTimexs:timexs:decimalxs:integerxs:float, and xs:double, and if no xxforms:format attribute is present on the control, formatting is based on properties.

The xxforms:format attribute

Orbeon Forms provides an extension attribute, xxforms:format, to control formatting locally on:

  • xforms:output
  • xforms:input

xxforms:format must contain an XPath expression, which is evaluated by the XForms engine whenever the value bound to the 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?).

Example:

<xforms:output
  ref="date"
  xxforms:format="format-date(xs:date(.), '[MNn] [D], [Y]', 'en', (), ())"/>
<xforms:output
  ref="size"
  xxforms:format="format-number(., '###,##0')"/>


Iteration of XForms actions over sequences

Compatibility note

  • With Orbeon Forms 4.0: use the XForms 2.0 iterate attribute (builds of Orbeon Forms from March 10, 2012).
  • With Orbeon Forms 3.9 and earlier:, use the xxforms:iterate or exforms:iterate extension. These are still supported in Orbeon Forms 4.0 for backward compatibility.

Usage

Consider the following instances:

<xforms:instance id="main-instance">e
  <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"
     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, 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>

This documentation has moved here.

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:

  • Multiple <xforms:select1 appearance="full"> point to the same node.

  • You enable deferred event handling on the client.

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.


Comments