Orbeon Forms User Guide

XForms Reference, Part 2

1. Introduction

This is Part 2 of a two-part document. This part focuses on extensions over XForms provided by Orbeon Forms, as well as XForms engine configuration.

Please be sure to visit Part 1 as well.

2. Extensions

2.1. Read-Only Mode

2.1.1. Making an Entire Instance Read-Only

You often want to present a form without allowing the user to enter data. An easy solution is to use the readonly MIP in the model. By making for example the root element of an instance read-only, all the controls bound to any node of that instance will appear read-only (because the read-only property is inherited in an instance):

<xforms:instance id="my-form"><form>...</form></xforms:instance><xforms:bind nodeset="instance('my-form')" readonly="true()"/>

2.1.2. Static Appearance for Read-Only Mode

Sometimes, read-only controls don't appear very nicely in web browsers. For example, a combo box will appear grayed out. It maybe be hard to read, and there is not much point showing a combo box since the user can't interact with it. Furthermore, with some browsers, like IE 6 and earlier, it is not even possible to make disabled controls appear nicer with CSS. In order to make read-only versions of forms look nicer, Orbeon Forms supports a special extention attribute that allows you to produce a "static" appearance for read-only controls. You enable this on your first XForms model:

<xforms:model xxforms:readonly-appearance="static">...</xforms:model>

The attribute takes one of two vales: static or dynamic (the default). When using the value static, read-only controls do not produce disabled HTML form controls. This has one major limitation: you can't switch a control back to being read-write once it is displayed as read-only.

You can also set the xxforms:readonly-appearance attribute directly on individual XForms controls.

See the Government Forms sample application's View Read-Only option for an example of this feature in action.

2.2. Formatting

2.2.1. 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?).

2.2.2. xforms:input

When using xforms:input and a bound xs:date type, you can control the formatting of the date using the xxforms:format extension attribute on the xforms:input control. For example:

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

2.2.3. 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')"/>

2.2.4. 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.
  • 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].

2.3. XForms 1.1 Extensions

2.3.1. Media Type for xforms:output

In XForms 1.0, xforms:output is used to display text. However, based on a proposal in a draft version of XForms 1.1, Orbeon Forms supports a mediatype attribute on that element.

Image Types

For the <xforms:output> control to display an image, you need to:

  • Have a mediatype attribute on the <xforms:output>. That attribute must refer to an image, such as image/* or image/jpeg.

  • Use the value attribute on <xforms:output> or bind to the control to a node without type or with an xs:anyURI type.

The resulting value is interpreted a URI pointing to an image. The image will display in place of the xforms:output. When a single-node binding is used, it is possible to dynamically change the image pointed to. For example:

<xforms:output mediatype="image/*" value="'/images/moon.jpg'"/>
<xforms:model><xforms:instance><image-uri/></xforms:instance><xforms:bind nodeset="image-uri" type="xs:anyURI"/></xforms:model>...<xforms:output mediatype="image/*" ref="image-uri"/>
Note
It is not yet possible to directly embed image data in an XForms instance using the xs:base64Binary type.
HTML Type

When an xforms:output control has a mediatype attribute with value text/html, the value of the node to which the control is bound is interpreted as HTML content. Consider the following XForms instance:

<xforms:instance id="my-instance"><form><html-content>This is in &lt;b&gt;bold&lt;/b&gt;!</html-content></form></xforms:instance>

You bind an xforms:output control to the html-content node as follows:

<xforms:output ref="instance('my-instance')/html-content" mediatype="text/html"/>

This will display the result as HTML, as expected: "This is in bold!". If the mediatype is not specified, the result would be instead: "This is in <b>bold</b>!". In the XForms instance, the HTML content must be escaped as text. On the other hand, the following content will not work as expected:

<xforms:instance><form><html-content>This is in in<b>bold</b>!</html-content></form></xforms:instance>
Note
When using a mediatype="text/html", an HTML <div> element will be generated by the XForms engine to hold the HTML data. As in HTML a <div> cannot be embedded into a <p>, if you have a <xforms:output mediatype="text/html"> control, you should not put that control into a <xhtml:p>.

2.3.2. origin Attribute on xforms:insert Action

Orbeon Forms supports the XForms 1.1 origin attribute on the xforms:insert action. This attribute allows specifying the source node to use as template. This allows storing templates separately from the node-set specified by the nodeset attribute. For example:

<xforms:insert nodeset="address" at="last()" position="after" origin="instance('template-instance')"/>

The template copied in this case comes from an XForms instance:

<xforms:instance id="template-instance"><address><street><number/><name-1/><name-2/></street><apt/><city/><state/><zip/></address></xforms:instance>

2.3.3. context Attribute on xforms:insert Action

Orbeon Forms supports the XForms 1.1 context attribute on the xforms:insert action. This attribute allows specifying a context for insertion, which along with the origin attribute allows inserting content into elements:

<xforms:insert context="instance('main-instance')/books" nodeset="book" origin="instance('book-instance')"/>

With original instances as follows:

<xforms:instance id="main-instance"><instance><books/></instance></xforms:instance><xforms:instance id="book-instance"><book><title>Cosmos</title><author>Carl Sagan</author></book></xforms:instance>

The result of a first insertion is:

<xforms:instance id="main-instance"><instance><books><book><title>Cosmos</title><author>Carl Sagan</author></book></books></instance></xforms:instance>

2.3.4. validate and relevant Attributes on xforms:submission

Orbeon Forms supports the XForms 1.1 validate and relevant attributes on xforms:submission. For more information, please visit the XForms 1.1 specification.

2.3.5. Conditional Execution and Iteration of XForms Actions

Orbeon Forms supports the XForms 1.1 if and while attributes on XForms action elements. For more information, please visit the XForms 1.1 specification.

2.4. XPath Extension Functions

Orbeon Forms implements some extension functions which can be used from XPath expressions in XForms documents.

2.4.1. XSLT 2.0 Functions

When using XPath 2.0, the following functions from XSLT 2.0 are also available:

2.4.2. Orbeon Forms Functions

The following functions are implemented:

  • xxforms:if().

    This function implements the semantic of the XForms 1.0 if() function. See Note About XPath 2.0 Expressions for more details.

  • xxforms:call-xpl($xplURL as xs:string, $inputNames as xs:string*, $inputElements as element()*, $outputNames as xs:string+) as document-node()*.

    This function lets you call an XPL pipeline.

    1. The first argument, $XPLurl, is the URL of the pipeline. It must be an absolute URL.
    2. The second argument, $inputNames, is a sequence of strings, each one representing the name of an input of the pipeline that you want to connect.
    3. The third argument, $inputElements, is a sequence of elements to be used as input for the pipeline. The $inputNames and $inputElements sequences must have the same length. For each element in $inputElements, a document is created and connected to an input of the pipeline. Elements are matched to input name by position, for instance the element at position 3 of $inputElements is connected to the input with the name specified at position 3 in $inputNames.
    4. The fourth argument, $outputNames, is a sequence of output names to read.
    5. The function returns a sequence of document nodes corresponding the output of the pipeline. The returned sequence will have the same length as $outputNames and will correspond to the pipeline output with the name specified on $outputNames based on position.

    The example below shows a call to the xxforms:call-xpl function:

    xxforms:call-xpl ('oxf:/examples/sandbox/xpath/run-xpath.xpl', ('input', 'xpath'), (instance('instance')/input, instance('instance')/xpath), 'formatted-output')/*, 'html')
  • xxforms:evaluate($xpath as xs:string) as item()*.

    The xxforms:evaluate() function allows you to evaluate XPath expressions dynamically. For example:

    <xforms:input ref="xxforms:evaluate(concat('instance(''my-instance'')/document', my-xpath))"><xforms:label>...</xforms:label></xforms:input>
  • xxforms:serialize($item as node(), $format as xs:string?) as xs:string.

    The xxforms:serialize() function allows you to serialize an XML node to XML, HTML, XHTML or text. For example:

    <xforms:bind nodeset="my-html" calculate="xxforms:serialize(instance('my-instance'), 'html')"/>
  • xxforms:repeat-current($repeat-id as xs:string?) as node().

    The xxforms:repeat-current() function allows you to obtain a reference to an enclosing xforms:repeat's current iteration node. It takes one optional string parameter. If present, the id of the enclosing xforms:repeat is searched. If absent, the function looks for the closest enclosing xforms:repeat.

    <xforms:repeat nodeset="employee" id="employee-repeat"><tr><td><!-- The context is being set to another instance that controls the visibility of the group. --><xforms:group ref="instance('control-instance')/input"><!-- Using xxforms:repeat-current() allows reclaiming the context of the repeat iteration. --><xforms:input ref="xxforms:repeat-current('employee-repeat')/name"><xforms:label>Employee Name</xforms:label></xforms:input></xforms:group></td></tr></xforms:repeat>

    The xxforms:repeat-current() function must be called from within an xforms:repeat element.

  • xxforms:context($element-id as xs:string?) as node().

    The xxforms:context() function allows you to obtain the evaluation context for an enclosing xforms:group, xforms:repeat, or xforms:switch. It takes one optional string parameter containing the id of an enclosing XForms element.

    <xforms:group ref="employee" id="employee-group"><!-- The context is being set to another instance that controls the visibility of the group. --><xforms:group ref="instance('control-instance')/input"><!-- Using xxforms:context() allows reclaiming the context of the enclosing group. --><xforms:input ref="xxforms:context('employee-group')/name"><xforms:label>Employee Name</xforms:label></xforms:input></xforms:group></xforms:group>
  • xxforms:instance($instance-id as xs:string) as element()?.

    The xxforms:instance() function works like the standard instance() function except that it searches for instances in all the models of the XForms document (the standard instance() function only searches within the current XForms model).

    <xforms:model id="main-model"><xforms:instance id="main-instance">...</xforms:instance></xforms:model><xforms:model id="resources-model"><xforms:instance id="resources-instance">...</xforms:instance></xforms:model>...<xforms:group model="main-model"><xforms:output value="xxforms:instance('resources-instance')/titles/company-information"/></xforms:group>
  • xxforms:index($repeat-id as xs:string?) as xs:integer.

    The xxforms:index() function behaves like the standard XForms index() function, except that its argument is optional. When the argument is omitted, the function returns the index of the closest enclosing <xforms:repeat> element. This function must always be used within <xforms:repeat> otherwise an error is raised.

    <xforms:repeat nodeset="employee" id="employee-repeat"><div><xforms:trigger><xforms:label>Add One</xforms:label><xforms:insert ev:event="DOMActivate" nodeset="../employee" at="xxforms:index()"/></xforms:trigger></div></xforms:repeat>

2.4.3. eXForms Functions

eXForms is a suggested set of extensions to XForms 1.0, grouped into different modules. Orbeon Forms supports the exf:mip module, which includes the following functions:

  • exf:relevant()

  • exf:readonly()

  • exf:required()

Orbeon Forms also supports the following from the sorting module:

  • exf:sort()

eXForms functions live in the http://www.exforms.org/exf/1-0 namespace, usually bound to the prefix exf or exforms.

2.5. JavaScript Integration

2.5.1. Rationale

While XForms gets you a long way towards creating a dynamic user-friendly user interface, there are some dynamic behaviors of the user interface that cannot be implemented easily or at all with XForms, or you might already have some JavaScript code that you would like to reused. A JavaScript API is provided to handle those cases, or other use cases involving JavaScript that you might have.

2.5.2. Getting and Setting Controls Value

In JavaScript, you get the current value of an XForms control var value = ORBEON.xforms.Document.getValue("myControl") where myControl is the id of the XForms control, for instance: <xforms:input id="myControl">.

You set the value of an XForms control with ORBEON.xforms.Document.setValue("myControl", "42") where myControl is the id of the XForms control, and 42 the new value. Setting the value with JavaScript is equivalent to changing the value of the control in the browser. This will trigger the recalculation of the instances, and the dispatch of the xforms-value-changed event. More formally, the Value Change sequence of events occurs.

As an example, consider you have the model below. It declares an instance with two elements foo and bar, where bar is a copy of foo, implemented with a calculate MIP.

<xforms:model><xforms:instance id="instance"><instance><foo>42</foo><bar/></instance></xforms:instance><xforms:bind nodeset="/instance/bar" calculate="/instance/foo"/></xforms:model>

The input control below is bound to foo, and the output control is bound to bar. When activated, the trigger executes JavaScript with the <xxforms:script> action. It increments the value of the input control bound to foo. When this happens the value displayed by the output control bound to baris incremented as well, as bar is a copy of foo.

<xhtml:p><xforms:input ref="foo" id="foo"><xforms:label class="fixed-width">Value of foo:</xforms:label></xforms:input></xhtml:p><xhtml:p><xforms:output ref="bar"><xforms:label class="fixed-width">Value of bar:</xforms:label></xforms:output></xhtml:p><xhtml:p><xforms:trigger><xforms:label>Increment foo with JavaScript</xforms:label><xxforms:script ev:event="DOMActivate">var fooValue = ORBEON.xforms.Document.getValue("foo"); ORBEON.xforms.Document.setValue("foo", Number(fooValue) + 1);</xxforms:script></xforms:trigger></xhtml:p>

2.5.3. Dispatching Events

You can dispatch your own events from JavaScript by calling the function ORBEON.xforms.Document.dispatchEvent(). The parameters to this function are:

targetId Mandatory Id of the target element. The element must be an element in the XForms namespace: you cannot dispatch events to HTML elements. In addition, the id must identify either a relevant and non-readonly XForms control, or a model object that supports event handlers such as <xforms:model>, <xforms:instance>, or <xforms:submission>.
eventName Mandatory

Name of the event.

Warning

For security reasons, by default Orbeon Forms prohibits client-side JavaScript from dispatching any external events except DOMActivate, DOMFocusIn and DOMFocusOut. Furthermore, these events can only be dispatched to relevant and non-readonly XForms controls. In order to enable dispatching of custom events, you must first add the xxforms:external-events attribute on the first <xforms:model> element, for example:

<xforms:model xxforms:external-events="acme-super-event acme-famous-event">...</xforms:model>

This attribute contains a space-separated list of event name. In this example, you explicitly enable your JavaScript code to fire the two events acme-super-event and acme-famous-event to any relevant and non-readonly XForms controls, or to any model object supporting event handlers. Note that you can only enable custom events, but you cannot enable standard XForms or DOM events in addition to DOMActivate, DOMFocusIn and DOMFocusOut.

Since the event handlers for custom events can be called by JavaScript code that runs on the client, you need to be aware that these handlers can potentially be activated by anybody able to load the form in his browser.

form Optional The form object that corresponds to the XForms form you want to dispatch the event to. This argument is only needed when you have multiple "XForms forms" on the same HTML page. Typically, this would only happens if you are running your form in a portal and you have multiple portlets using XForms on the same page. When the parameter is not present or null, the first form on the HTML page with the class xforms-form is used.
bubbles Optional Optional boolean indicating if this event bubbles, as defined in DOM2 Events. The default value depends on the definition of the custom event.
cancelable Optional Optional boolean indicating if this event bubbles, as defined in DOM2 Events. The default value depends on the definition of the custom event.
incremental Optional When false the event is sent to the XForms server right away. When true the event is sent after a small delay, giving the opportinuty for other events that would occur during that timespan to be aggregated with the current event.
ignoreErrors Optional When set to true, errors happening while the event is dispatched to the server are ignored. This is in particular useful when you are using a JavaScript timer (e.g. window.setInterval()) that runs a JavaScript function on a regular interval to dispatch an event to the server, maybe to have part of the UI updated. In some cases, you might not want to alert the user when a there is a maybe temporary communication error while the event is being dispatched to the server. In those cases, you call call dispatchEvent with ignoreErrors set to true.

In most cases, you only need to call dispatchEvent() with a target id and event name, as in:

ORBEON.xforms.Document.dispatchEvent("main-model", "do-something");

An event handler for the custom event can be in an XForms model or control, and can execute any valid XForms action. Here an action is explicatly declared to handle the do-something even on the XForms model:

<xforms:model id="main-model" xxforms:external-events="do-something"><xforms:action ev:event="do-something"><xforms:setvalue ref="first-name" value="instance('default-values')/first-name"/><xforms:toggle case="first-name-case"/></xforms:action></xforms:model>

2.6. Attribute Value Templates

Certain attributes in XForms are literal values defined by the form author at the time the form is written, as opposed to being evaluated at runtime. Examples include the action attribute on <xforms:submission>, or the resource attribute on <xforms:load>.

To improve this, Orbeon Form supports a notation called Attribute Value Templates (AVTs), borrowed from XSLT, which allows including XPath expressions within attributes. You include XPath expressions in attributes by enclosing them within curly brackets ({ and }). Consider this example:

<xforms:load resource="/forms/detail/{instance('documents-instance')/documents/document[index('documents-repeat')]/id}"/>

When <xforms:load> is executed, the resource attribute is evaluated. The results is the concatenation of /forms/detail/ and of the result of the expression within brackets instance('documents-instance')/documents/document[index('documents-repeat')]/id. If the id element pointed to contains the string C728595E0E43A8BF50D8DED9F196A582, the resource attribute takes the value /forms/detail/C728595E0E43A8BF50D8DED9F196A582.

AVTs are currently supported only within certain attributes:

  • <xforms:submission>: action, xxforms:username, xxforms:password, xxforms:readonly and xxforms:shared attributes.

  • <xforms:dispatch>: name attribute.

  • <xforms:load>: resource attribute.

  • <xforms:setfocus>: control attribute.

There are plans to support AVTs in more places in the future.

2.7. Dialogs

2.7.1. The xxforms:dialog Control

You declare dialogs directly under the <xhtml:body> element with:

<xxforms:dialog id="my-dialog-id" appearance="full | minimal" level="modeless" close="true" draggable="true"><xforms:label>Dialog title</xforms:label>Content of the dialog (XHTML + XForms)</xxforms:dialog>
  • When you have appearance="full" on the dialog, you define the title of the dialog with the embedded <xforms:label> element.
  • Inside an <xxforms:dialog> you can use all the XHTML and XForms elements you can normally use elsewhere on the page. You can have other XForms controls, or show anything you would like to with HTML.
  • The attributes on the <xxforms:dialog> are as follows:
id Mandatory The ID of the dialog. You reference this ID when opening the dialog with <xxforms:show dialog="my-dialog-id">.
appearance Optional. Possible values are:
  • full (default)
  • minimal
You can set the appearance to either full or minimal:
  • The first screenshot below shows a dialog with appearance="full" while the second one shows a dialog with appearance="minimal".
  • In general, you will use the minimal dialog when you want to show a limited set of information which is related to a certain element in the page. The minimal dialog is sometime also referred to as a "drop-down dialog".
  • Some of the other attributes on <xxforms:dialog> can only be used for the full or the minimal dialog. You will find more details on this below.

level Optional. Can only be used appearance is set to full. Possible values are:
  • modal (default)
  • modeless
When set to modal the rest the page is grayed out and you can't interact with any ontrol on the page outside of the dialog. When set to modeless you can still use other controls on the page.
close Optional. Can only be used appearance is set to full. Possible values are:
  • true (default)
  • false
A "x" is shown in the dialog title bar when close is set to true. If you specify close="false", then you should provide a way to close the dialog, for instance by having you own "Close" button inside the dialog. This is typically useful when you want to force users to enter some data before proceeding and you don't want them to cancel the current operation by closing the dialog.
draggable Optional. Can only be used appearance is set to full. Possible values are:
  • true (default)
  • false
When set to false, you won't be able to move dialog on the page by using drag and drop in the dialog title bar.

2.7.2. The xxforms:show and xxforms:hide Actions

[To be completed]

2.7.3. The xxforms-dialog-open and xxforms-dialog-close Events

[To be completed]

2.8. Other Extensions

2.8.1. XForms Submission - HTTP Authentication

The xforms:submission element supports optional xxforms:username and xxforms:password attributes that allow specifying HTTP authentication credentials. You can specify either both attributes, or only the xxforms:username attribute. The latter case is equivalent to setting the value of xxforms:password to an empty string.

<xforms:submission id="save-submission" ref="instance('my-instance')" method="put" action="/exist/rest/ops/my-file.xml" replace="none" xxforms:username="admin" xxforms:password=""/>

2.8.2. XForms Submission/Load - Loading Indicator

When an xforms:submission with replace="all" is executed, in general, the browser will load another page. While this happens, the loading indicator, by default shown in red at the top right of the window, is displayed. However, when the browser is served not a web page but say a ZIP file, the browser might ask you in you want to download it, and then stay in the current page. When this happens, the loading indicator does not go away.

In those cases where you know that the target page does not replace the current page, you can prevent the loading indicator from being displayed by adding the xxforms:show-progress="false" attribute:

<xforms:submission xxforms:show-progress="false"/>

Similarly the xxforms:show-progress="false" attribute can be used with the xforms:load action:

<xforms:load xxforms:show-progress="false"/>

2.8.3. XForms Submission/Load - Target

You can use the xxforms:target attribute on both xforms:submission and xforms:load. It behaves just like the HTML target attribute. When used on xforms:submission, it makes sense to use this attribute only when you have a replace="all", as the replace="instance" doesn't load another page.

2.8.4. xxforms:script Action

The xxforms:script action allows you to call client-side JavaScript as a result of XForms events:

<xforms:action ev:event="xforms-value-changed"><xforms:setvalue ref=".">test</xforms:setvalue><xxforms:script>var v = 2; myValueChanged(v);</xxforms:script></xforms:action>
Note

xxforms:script actions are currently always executed last in a sequence of XForms actions, even if they appear before other XForms actions.

2.8.5. Read-Only XForms Instances with xxforms:readonly

Orbeon Forms supports an extension attribute, xxforms:readonly, on the <xforms:instance> and <xforms:submission> elements. When set to true, this attribute signals that once loaded, the instance is read-only, with the following consequences:

  • The instance is loaded into a smaller, more efficient, read-only data structure in memory.

  • Instance values cannot be updated, and no Model Item Properties (MIPs) can be assigned with <xforms:bind> to the instance. But a read-only instance can be replaced entirely by an <xforms:submission replace="instance">

  • When using client-side state handling, less data may be transmitted between server and client.

Read-only instances are particularly appropriate for loading internationalization resources, which can be large but don't change. Example:

<xforms:instance id="resources-instance" src="/forms/resources/en" xxforms:readonly="true"/>

The xxforms:readonly attribute on <xxforms:instance> determines if the instance is read-only until that instance is being replaced. After an instance is replaced, it can be read-only or not irrelevant of the of xxforms:readonly on <xxforms:instance>. When the instance is replaced, the replaced instance is read-only if and only if the <xforms:submission> that does the replacement has a attribute xxforms:readonly="true".

2.8.6. Sharing of Read-Only XForms Instances with xxforms:shared

Orbeon Forms supports an extension attribute, xxforms:shared, on the <xforms:instance> and <xforms:submission> elements. This attribute can be used only when an XForms instance is marked as read-only with xxforms:readonly="true". xxforms:shared can take two values: document (the default if the attribute is not specified) and application. When application is specified:

  • The instance can be shared at the application level identified just by its source URL.

  • The instance is not stored into the XForms document's state, but in a global cache, therefore potentially saving memory. If, upon loading an XForms document, the instance is found in the cache, it is directly retrieved from the cache. This can save time especially if the URL can take significant time to load.

  • The URL must refer to a constant XML document and authorization credentials such as username and password should not cause different data to be loaded.

Here is how you use the attribute on <xforms:instance>:

<xforms:instance id="resources-instance" src="/forms/resources/en" xxforms:readonly="true" xxforms:shared="application"/>

When used on <xforms:submission>, the submission has to use method="get" method and replace="instance":

<xforms:submission serialize="false" action="/forms/resources/fr" method="get" replace="instance" instance="resources-instance" xxforms:readonly="true" xxforms:shared="application"/>

You set the size of the shared instances cache using a property in properties.xml:

<property as="xs:integer" name="oxf.xforms.cache.shared-instances.size" value="10"/>

You can force the XForms engine to remove a shared instance from the cache by dispatching the xxforms-instance-invalidate event to it. The next time an XForms document requires this instance, it will not be found in the cache and therefore reloaded. Example:

<xforms:action ev:event="DOMActivate"><xforms:send submission="save-submission"/><xforms:dispatch name="xxforms-instance-invalidate" target="data-to-save-instance"/></xforms:action>

When using xxforms:readonly="true", another attribute, xxforms:ttl, can be used to set a time to live for the instance in cache. This duration is expressed in milliseconds and has to be greater than zero. When a shared instance if found in cache but has an associated time to live, if it was put in the cache more than time to live milliseconds in the past, then the instance is discarded from the cache and retrieved again by URI as if it had not been found in cache at all. The following example expires the shared instance after one hour:

<xforms:instance id="resources-instance" src="/forms/resources/en" xxforms:readonly="true" xxforms:shared="application" xxforms:ttl="3600000"/>
Warning
When using xxforms:shared="application", be sure that the data contained in the instance does not contain information that could be inadvertently shared with other XForms documents. It is recommended to use it to load localized resources or similar types of data.

2.8.7. Controlling Item Sets Refreshes with xxforms:refresh-items

XForms specifies that items and itemsets are re-evaluated when processing xforms-refresh. This may happen quite often, and may lead to time-consuming re-evaluations especially when there are many or large itemsets.

Orbeon Forms supports an extension attribute, xxforms:refresh-items, on the <xforms:select> and <xforms:select1> elements. When set to true (the default), items and itemsets are re-computed upon xforms-refresh event processing. When set to false, this attribute signals that once computed, the set of items for the control will not be recomputed upon xforms-refresh event processing.

If you know that itemsets do not change over time, setting xxforms:refresh-items to false disables refreshing of the items during xforms-refresh and may yield significant performance improvements. For example:

<xforms:select1 ref="state" xxforms:refresh-items="false"><xforms:label>State</xforms:label><xforms:item><xforms:label/><xforms:value/></xforms:item><xforms:itemset nodeset="instance('schema-instance')/xs:simpleType[@name = 'state']//xs:enumeration"><xforms:label ref="@value"/><xforms:value ref="@value"/></xforms:itemset></xforms:select1>

2.8.8. Trees with the xxforms:tree Appearance

[TODO: describe the Orbeon Forms xxforms:tree appearance on xforms:select and xforms:select1]

2.8.9. Menus with the xxforms:menu Appearance

[TODO: describe the Orbeon Forms xxforms:tree appearance on xforms:select1]

3. Configuration

3.1. State Handling

3.1.1. Rationale

The Orbeon Forms XForms engine requires keeping processing state while operating on an XForms page. Such state includes the current values of XForms instances, selected repeated elements, and more. With Orbeon Forms, XForms state information can be handled in one of two ways:

  • Server-side: in this case, state information is stored on the server. Only very little state information circulates between client and server. The most frequently used state information is stored in memory. Less frequently used state information is stored on disk in a local database.

    Benefits of the approach:

    • Resulting HTML page are smaller. HTML pages increase in size as more XForms controls are used, but they don't increase in size proportionally to the size of XForms instances.

    • Small amounts of data circulate between the client browser and the Orbeon Forms XForms server.

    • This means that very large XForms instances can be processed without any impact on the amount of data that is transmitted between the client and the server.

    Drawbacks of the approach:

    • The Orbeon Forms XForms server needs to be stateful. It uses server memory to store state information even when no request is being processed. This creates additional demand for resources on the server and slightly complicates the task of tuning the server.

    • State information can become unavailable when sessions expire or when the server is restarted. When state information becomes unavailable for a page, that page will no longer function unless it is reloaded.

    Note
    Orbeon Forms ensures that it is possible to open multiple client browser windows showing the same page within the same session.
  • Client-side: in this case, static initial state information is sent along with the initial HTML page, and dynamic state is exchanged over the wire between the client browser and the Orbeon Forms XForms server when necessary.

    Benefits of the approach:

    • The Orbeon Forms server is entirely stateless. It only requires memory while processing a client request. It can be restarted without consequence for the XForms engine.

    • State information does not expire as long as the user keeps the application page open in the web browser.

    Drawbacks of the approach:

    • Resulting HTML pages are larger. In particular, the size of state data grows when XForms instances grow, regardless of whether many XForms controls are bound to instance data.

    • More data circulates between the client browser and the Orbeon Forms XForms server.

    Note
    Orbeon Forms compresses and encrypts XForms state information sent to the client.

By default, Orbeon forms store XForms state information on the server. Please change this default to client-side only if you have well understood the tradeoffs explained above.

3.1.2. Configuring State Handling

State handling can be configured globally for all pages, or locally for each individual page served. Global configuration is performed in properties.xml with the oxf.xforms.state-handling property. When missing or set to client, state is stored client-side. When set to server, state is stored server-side. For example:

<!-- Store state on the server --><property as="xs:string" name="oxf.xforms.state-handling" value="server"/>

The global configuration can be overridden for each page by setting the xxforms:state-handling attribute in the page. This attribute can be set on the root element of the XHTML page, or on the first xforms:model element. Only the first such attribute encountered by the XForms engine is used:

<xforms:model xxforms:state-handling="client">...</xforms:model>

When storing state on the server, the maximum size of the data to be stored globally in memory can be selected using the oxf.xforms.store.application.size property. The size is specified in bytes:

<!-- Allow a maximum of 20 MB of state information among all users --><property as="xs:integer" name="oxf.xforms.store.application.size" value="20000000"/>

When the allowed memory space for state information is full, Orbeon passivates state information to a local eXist database. Configuration parameters for the connection to the eXist database can be changed. The defaults are as follows:

<!-- Disk-based store connection information --><property as="xs:string" name="oxf.xforms.store.application.username" value="guest"/><property as="xs:string" name="oxf.xforms.store.application.password" value="guest"/><property as="xs:anyURI" name="oxf.xforms.store.application.uri" value="xmldb:exist:///"/><property as="xs:string" name="oxf.xforms.store.application.collection" value="/db/orbeon/xforms/cache/"/>

Whether state information is kept client-side or server-side, a property controls whether the XForms engine should try to optimize state reconstruction by using a cache. This property should usually be set to true:

<!-- This should usually be set to "true" --><property as="xs:boolean" name="oxf.xforms.cache.document" value="true"/>

If the above property is set to true, the number of XForms documents that can be held in that document cache at a given time is configured with the following property:

<!-- Store at most 10 documents in the cache --><property as="xs:integer" name="oxf.xforms.cache.documents.size" value="10"/>

Note that this represents XForms documents in a particular state of interaction with a user, which means that if to users load the same XForms page two entries will be needed in the cache.

3.2. JavaScript and CSS Resources

3.2.1. Minimal Resources

Most JavaScript and CSS files used by the XForms engine are available in two versions:

  • A full version, which may contain comments, spaces, longer identifiers, etc.

  • A minimal version, which is usually much smaller

Both versions work exactly the same. For development and debugging of the XForms engine itself, the full version is easier to work with. But if you never work directly with these JavaScript and CSS files, as well as for deployment, the minimal versions are recommended as they will load faster in the user's web browser. You enable minimal resources in properties.xml as follows:

<!-- Enable minimal resources --><property as="xs:boolean" name="oxf.xforms.minimal-resources" value="true"/>

3.2.2. Combined Resources

Serving CSS and JavaScript can have a high performance cost on page loads. This is particularly important with the intensive use of JavaScript in Orbeon Forms. In particular, it can be shown that serving many small files is slower than serving a single large file. In theory, HTTP pipelining can improve very much on this, but this is (very unfortunately) useless in practice at the time of writing because Internet Explorer doesn't implement it at all and Firefox / Mozilla do implemente it but do not enable it by default. This is why Orbeon Forms supports the option of combining the multiple JavaScript and CSS files required for a given XForms page into a single JavaScript file and a single CSS file.

You enable this feature in properties.xml as follows

<!-- Enable combined resources --><property as="xs:boolean" name="oxf.xforms.combined-resources" value="true"/>

When this is enabled, Orbeon Forms refers to a single JavaScript file and a single CSS file for XForms-related functionality. The URL identifies special resources needed by the page, for example:

<link rel="stylesheet" href="/ops/xforms-server/xforms-range-autocomplete-min.css" type="text/css"/><script type="text/javascript" src="/ops/xforms-server/xforms-range-autocomplete-min.js"/>

This in short tells the XForms server to produce the minimal CSS and JavaScript for the XForms engine including support for the "range" and "autocomplete" features. Note that you don't have to write these URLs yourself: the Orbeon Forms XForms engine adds them automatically to your page.

When the Orbeon Forms XForms server receives a request for a combined resource, it determine what files need to be combined and outputs them all together. Furthmore, for CSS files, all URLs referred to with url() are rewritten, so that links to images, in particular, remain correct.

In addition, you can enable caching of combined resources with:

<!-- Enable caching of combined resources --><property as="xs:boolean" name="oxf.xforms.cache-combined-resources" value="true"/>

This cache works differently from other Orbeon Forms caches, as the result is stored in the resources, typically under:

WEB-INF/resources/xforms-server/

One benefit of this mechanism is that it allows making such combined files to be served by an Apache front-end.

3.3. Debugging XForms Pages

3.3.1. Enabling XForms Logging

When a fatal error occurs, the XForms engine throws a Java exception which either results in an error page in your web browser (when the error occurrs during page initialization) or in an error message at the top of the displayed XForms page (when the error occurs during an Ajax request after the page is loaded). The main Java exception is also logged on the server. Often, this provides enough information to the developer to figure out what went wrong. When this is not sufficient, the best tool available is the XForms engine logging facility. To enable it, make sure you uncomment the following lines in config/log4j.xml:

<category name="org.orbeon.oxf.xforms.processor.XFormsServer"><priority value="debug"/></category><category name="org.orbeon.oxf.xforms.processor.XFormsModelSubmission"><priority value="debug"/></category>
Note

You must restart your Servlet container for those changes to be taken into account.

This setting enables verbose logging of the XForms engine's operations, in particular:

  • Dispatching of events.

  • Execution of actions.

  • Loading of instances.

  • Execution of submissions.

  • Resulting XForms instances.

  • XForms cache-related operations.

The following figure shows a sample XForms logging session in Orbeon Studio:

3.3.2. The Instance Inspector

The Instance Inspector allows you to visualize all the instances of your XForms page. You enable it by adding the following within your XForms page:

<widget:xforms-instance-inspector xmlns:widget="http://orbeon.org/oxf/xml/widget"/>

This is an example of how the Instance Inspector looks like in your page:

You can select which model and instand to view, and decide whether to see plain XML or formatted XML.

4. Migrating from XForms Classic to XForms NG

Migrating from XForms Classic to XForms NG consists in telling Orbeon Forms to use XForms NG, in making the necessary changes to adjust your XForms model and controls (this is necessary as XForms Classic was lacking in terms of compatibility with the XForms specification, and XForms NG on the contrary aims at implementing XForms 1.0 and XForms 1.1 fully), and (sometimes optionally) in making some architectural changes to your application:

  1. Configuring Orbeon Forms to use XForms NG.

    1. Identify in your page flow the pages that use XForms Classic. Those are defined by <page> elements with the xforms attribute, for example:

      <page id="my-page" path-info="/my/page" xforms="/my-page/xforms-model.xml" view="/my-page/view.xhtml"/>
    2. For each page identified in the previous step, locate the XForms model file referred by the xforms attribute. In most cases, this is a static XML file with a root element called <xforms:model>, for example:

      <xforms:model><xforms:instance>...</xforms:instance>...</xforms:model>

      You must now insert the content of that file into your XHTML page view. In most cases, the page view is a static XHTML file or a dynamic XSLT file that produces XHTML. Locate the <xhtml:head> element and insert the XForms model as a child of that element:

      <xhtml:html><xhtml:head><xhtml:title>My Page</xhtml:title><xforms:model><xforms:instance>...</xforms:instance>...</xforms:model></xhtml:head><xhtml:body>...</xhtml:body></xhtml:html>

      Alternatively, you can use XInclude to keep the XForms model external:

      <xhtml:html><xhtml:head><xhtml:title>My Page</xhtml:title><xi:include href="oxf:/my-page/xforms-model.xml"/></xhtml:head><xhtml:body>...</xhtml:body></xhtml:html>
    3. In the page flow, remove the xforms attribute on the <page> element:

      <page id="my-page" path-info="/my/page" view="/my-page/view.xhtml"/>

      What you have achieved at this point is migrating from XForms Classic's external XForms model specification to the up-to-date way of including XForms directly within XHTML. Note that this also allows you to use multiple XForms models simply by adding them as children of the <xhtml:head> element:

      <xhtml:html><xhtml:head><xhtml:title>My Page</xhtml:title><xforms:model id="main-model">...</xforms:model><xforms:model id="resources-model">...</xforms:model></xhtml:head><xhtml:body>...</xhtml:body></xhtml:html>
  2. Updating XForms model and controls.

    You are very likely to have to make further adjustments to your XForms controls and model. The following are possible things to look at:

    • The <xforms:submit> control requires a submission attribute referring to an existing <xforms:submission> element within an XForms model. Start creating an <xforms:submission> element, assign it an id, and then set the submission attribute on <xforms:submit>. For example:

      <xforms:submission id="default-submission" method="post" action="/services/save" replace="none"/>...<xforms:submit submission="default-submission"><xforms:label>Save</xforms:label></xforms:submit>
    • The <xxforms:if> and <xxforms:choose> extensions no longer work with XForms NG. Use <xforms:switch> or <xforms:group> with relevance instead. Note that you can often convert simply from:

      <xxforms:if test="/form/first-name = 'Joe'">...</xxforms:if>

      to:

      <xforms:group ref=".[/form/first-name = 'Joe']">...</xforms:group>
    • With XForms Classic, activacting a trigger would make the unique XForms instance of the unique XForms model available to Page Flow Controller processing (i.e. a PFC action, model and view could be activated). With NG, this is no longer the case and processing follows the XForms specification. This means in particular that if a submission fails because the submitted instance is invalid, that instance will never be sent by the XForms engine and will not, in particular, reach a page or service declared in the page flow (unless the XForms 1.1 validate="false" attribute on <xforms:submission> is set).

      Similarly, using triggers to perform insertions or deletions into XForms instances does not cause a submission to happen with XForms NG.

    • With XForms Classic, a submission would annotate an XForms instance with attributes such as xxforms:valid="true", etc. This is no longer the case with XForms NG.

  3. Architectural considerations.

    • Much of the work that was performed with page flow actions with XForms Classic can be implemented with XForms events and XForms actions. This means that you will tend to migrate functionality away from the PFC and towards XForms. This also means that you will use less XSLT to produce your pages, or even none at all, which is ideal as that is one less technology tha developers have to learn.

    • Because of the power of the <xforms:submission> element (which, with XForms 1.1, allows you to call any REST service), you are likely to move towards a service-oriented approach where your XForms page uses submissions that communicate with services. Such services may be external, or they may be implemented in Orbeon Forms and mapped in your page flow.