Orbeon Forms User Guide

XForms Reference, Part 1

1. Introduction

Web applications use forms to collect data from users. Orbeon Forms's form handling capabilities are based on XForms, namely the XForms 1.0 (Second Edition) W3C Recommendation and the XForms 1.1 W3C Working Draft. This section provides an introduction to XForms concepts and explains how to use XForms in your Orbeon Forms application.

Note

This document is considered a work in progress. While it does cover some generic features of XForms, it focuses before all on features specific to the Orbeon Forms XForms engine. For more information about XForms, please refer to the following resources:

We also recommend that you follow the Orbeon Forms Tutorial first!

This is Part 1 of a two-part document. This part focuses on how to use standard XForms features with Orbeon Forms.

Please be sure to visit Part 2 as well.

2. About XForms

2.1. Origin, Today, and Tomorrow

XForms 1.0 has been designed by the W3C based on experience with HTML forms. It was promoted to the rank of W3C Recommendation in October 2003, and a second edition of the specification was released in March 2006. The XForms Working Group at W3Cis as of July 2006 working on XForms 1.1, before embarking on XForms 1.2 or XForms 2.0. For more information about XForms, please refer to the FAQ.

As of July 2006, mainstream browsers (Internet Explorer, Mozilla / Firefox, Opera, Safari) do not support XForms natively, although XForms support in Mozilla is under way and plugins are available for Internet Explorer. However you can leverage the benefits of XForms today by using an Ajax-based XForms engine like the one provided in Orbeon Forms. The Orbeon Forms XForms engine transparently generates HTML forms and performs the work that would be done by an XForms-compliant browser, and you can leverage XForms today within the mainstream browsers that are already deployed in the marketplace.

For more information about the whys and therefores of server-side and Ajax-based XForms engines, please refer to the FAQ.

2.2. Benefits

Compared to HTML forms, XForms offers a higher level approach to forms. The benefits are that less programming is needed (less JavaScript, and less server-side programming), so forms are easier to create and modify. As an illustration, let's consider some facets of XForms:

  1. XML Representation of Forms. XForms clearly defines how data entered by the end-user is collected: it is stored in an XML document called an XForms instance, an initially empty, "skeletal" XML instance document that defines the structure of the data you wish to collect from the user, which is afterwards filled out with information collected from the user. For example, credit card information collected on a web site can be structured as follows:

    <credit-card><type/><number/><expiration-month/><expiration-year/></credit-card>

    The outcome of the user filling out a form collecting this information could be this complete XML document:

    <credit-card><type>visa</type><number>1234567812345678</number><expiration-month>8</expiration-month><expiration-year>2008</expiration-year></credit-card>

    An application using this data to do some processing (e.g. checking the validity of the credit card) receives the above XML document. There is no need to write code to go read HTTP request parameters, or to use a framework performing this task: XForms does it all.

  2. Declarative Constraints and Validation. More often than not, there are constraints on the data that can be entered by the end-user. For instance, in the example we just considered, the card number must have 16 digits and the expiration month must be a number between 1 and 12. Traditionally code must be written to check for those constraints. And more code must be written to handle error conditions (getting back to the page displaying the form and showing the appropriate error messages). All this is done is very simple and declarative way with XForms. For instance, checking that the expiration month is valid number between 1 and 12 can be done with:

    <xforms:bind nodeset="/credit-card/expiration-month" type="xs:integer" constraint=". >= 1 and 12 >= ."/>

    An error message can be attached to the "month" text field and if the end-user enters an invalid month the XForms engine will notice that the above constraint is not met and will display the error message. You do not have to write any code for this to happen. We will see later how you go about doing this with XForms in more details.

  3. Declarative Event Handling. User interfaces need to react to user event such as mouse clicks and character entry. With most UI frameworks, developers must register event handlers and implement them in JavaScript, Java, or other traditional imperative languages. With XForms, a set of predefined event handlers and actions are available, which cover a set of useful cases without requiring understanding the complex syntax and semantic of JavaScript or Java. For example, to set a value into an XForms instance, you write:

    <xforms:setvalue ref="/credit-card/expiration-month">11</xforms:setvalue>

    Once you have learned the simple built-in XForms actions, you can combine them in sequences to obtain more complex behavior.

3. Getting Started With the Orbeon Forms XForms Engine

3.1. The XForms Sandbox

The easiest way to get started with simple examples is to use the Orbeon Forms XForms Sandbox. This tool allows you to upload example XForms files from your web browser and to see the results directly. You can access the XForms sandbox:

  • Online: visit this link to access the online public XForms Sandbox.

  • Locally: if this documentation is produced by your local installation of Orbeon Forms, visit this link.

After submitting an XHTML + XForms file, the result, or errors, should display. If you have changed your local XForms file, reloads that page in your browser and this will upload again your local XForms file and the XForms Sandbox will run the new version. To select another file to upload use your browser quotes "back" button to return to the main XForms sandbox page.

4. Programming With XForms 1.0

4.1. XForms Model

4.1.1. Introduction

To help in our exploration of XForms we consider a specific example: an XForms Credit Card Verifier. This example displays a simple form asking for a credit card number and related information to be entered, as shown on the screenshot to the right. The information entered by the end-user is validated by a set of rules and errors are flagged in red.

First, the information contained in the form is stored in an XML document called an XForms instance, which is the skeleton or shell that will contain the data captured by the form. You define an XForms instance within an xforms:instance. In the Credit Card Verifier the unique XForms instance is declared with:

<xforms:instance id="credit-card-instance"><credit-card><type/><number/><expiration-month/><expiration-year/><verification-code/><valid/></credit-card></xforms:instance>

The XForms instance does not have to be empty of data: it can contain initial values for the form. Here we set the valid element to the value "false" by default:

<xforms:instance id="credit-card-instance"><credit-card><type/><number/><expiration-month/><expiration-year/><verification-code/><valid>false</valid></credit-card></xforms:instance>

XForms instances are always contained in an XForms model, which:

  1. Declares one or more XForms instance.

  2. Optionally, declares a set of rules attached to the XForms instances.

  3. Optionally, declares submissions.

At a minimum, the XForms instance above must be encapsulated as follows:

<xforms:model id="main-model"><xforms:instance id="credit-card-instance"><credit-card><type/><number/><expiration-month/><expiration-year/><verification-code/><valid>false</valid></credit-card></xforms:instance></xforms:model>

Note that instances and models can have an optional id attribute. If you have only one model and one instance, the id is optional, but it becomes very convenient when more than one model or instance are used.

4.1.2. Model Item Properties

In addition to one or more XForms instances, an XForms model can declare a set of "rules", called "model item properties". Let's write a set of rules for the above Credit Card Validation form. Specifically we want to:

  1. Check that the credit card number is a number and valid according to particular credit card rules

  2. Check that the expiration month is valid (integer between 1 and 12)

  3. Check that the expiration year is valid (4 digit number)

  4. Display the "verification code" line only if the card type is Visa or MasterCard

  5. Check that the verification code is valid only for Visa or MasterCard

You describe each one of those rules with an <xforms:bind> element in the XForms model. Rules apply to elements and attributes in the XForms instance. You specify the elements and attributes each rule applies to with an XPath expression in the mandatory nodeset attribute. In addition to the nodeset attribute you want to have at least one attribute specifying the essence of the rule. We go over the all the possible attributes later in this section, but first let's see how we can express the above rules for the Credit Card Verifier form:

  1. You specify that the credit card number must be a number with:

    <xforms:bind nodeset="number" type="xs:integer"/>

    The value of the type attribute is a W3C XML Schema simple type. You can see the list of simple types in the XML Schema primer. If the end-user enters an invalid credit card number (i.e. not a number), an error will be displayed as shows in the screenshot on the right.

  2. You can also constrain the value of an element or attribute with an XPath expression in the constraint attribute. For instance you specify that the expiration month must be an integer between 1 and 12 with:

    <xforms:bind nodeset="expiration-month" constraint=". castable as xs:integer and . >= 1 and 12 >= ."/>

    Note that we have decided here not to bother checking the expiration month if no credit card number was entered.

  3. Similarly, you check that the expiration year is a 4 digit number with:

    <xforms:bind nodeset="expiration-year" constraint=". castable as xs:integer and string-length(.) = 4"/>
  4. You hide the "verification code" text field for American Express cards with:

    <xforms:bind nodeset="verification-code" relevant="../type = 'visa' or ../type = 'mastercard'"/>

    The attribute we use here is relevant. By default, everything is relevant in the XForms instance. If a "relevant" rule is specified, the XPath expression is evaluated for each node in the nodeset, and if the expression returns false, then the node is not considered relevant. When a node is not relevant, the corresponding widget is not displayed (more on this later).

  5. Finally, you check that the verification code is entered for Visa and Mastercard:

    <xforms:bind nodeset="verification-code" constraint="/credit-card/type = ('visa', 'mastercard') and . castable as xs:positiveInteger"/>

    Because the verification-code element has both a relevant and a constraint attribute, we combine them on the same xforms:bind:

    <xforms:bind nodeset="verification-code" relevant="../type = 'visa' or ../type = 'mastercard'" constraint="/credit-card/type = ('visa', 'mastercard') and . castable as xs:positiveInteger"/>

XPath expressions in xforms:bind are by default relative to the root element of the first XForms instance. This allows you to write the first constraint above:

  • Relatively to the root element of the first XForms instance:

    <xforms:bind nodeset="number" type="xs:integer"/>
  • With an absolute path in the first XForms instance:

    <xforms:bind nodeset="/credit-card/number" type="xs:integer"/>
  • Referring explicitly to the "credit-card-instance" using the instance() function:

    <xforms:bind nodeset="instance('credit-card-instance')/number" type="xs:integer"/>

Now that we have seen a few examples of model item properties, let's go over all the XForms model item properties. Model item properties can essentially be used for 3 purposes:

Validation

The purpose of validation is to determine if the content of an element or attribute in the XForms instance is valid. Invalid values can have an impact on how a form is displayed (you might want to highlight errors and show some information to help the end-user to correct the issue). Also, the XForms engine makes sure that invalid data cannot be submitted. There are 3 ways to validate the content of an element or attribute:

  • required ― You can specify in the required attribute an XPath expression that determines if a value is required. The XPath can be as simple as true(), or more complex and depend on other values entered by the end-user. By default values are not required.

  • type ― In the type attribute you can specify a W3C XML Schema simple type. The type attribute complements the required attribute, but applies separately.

    In Addition, some XML schema types have special behavior:
    • xs:date ― The input field is complemented by a pop-up calendar. The user can enter a date manually, or use the calendar to select a date in the past or in the future. You can customize the calendar by copying the files in orbeon-resources-public.jar under ops/javascript/jscalendar to your resources directory. Your modified files in the resources will have a precedence over those found in orbeon-resources-public.jar.

  • constraint ― The constraint attribute supports any XPath expression that returns a boolean value. If false() is returned, then the value is considered invalid, otherwise it is considered valid.

Calculation

The purpose of calculations is to dynamically compute values. You do this with the calculate attribute:

  • calculate ― The content of the element or attribute will be set to the result of the evaluation of the XPath expression in the calculate attribute. This way you can automatically compute some values in the XForms instance based on other values, typically entered by the end-user. By default, nodes that contain calculated values are read-only.

Visibility

In general XForms instance nodes are not read-only and are relevant, which means that if an XForms control is bound to that node (e.g. a text field), the control is displayed and is editable by the end-user. You can change this by providing XPath expressions in the readonly and relevant attributes:

  • readonly ― If the XPath expression in readonly evaluates to true, the control will be displayed in non-editable mode. Typically, in an XHTML user interface only the current value is displayed, instead of displaying a form element, like a text field.

  • relevant ― If the XPath expression in relevant evaluates to false, the control will not be displayed at all.

4.2. XForms Controls

4.2.1. Available Controls

XForms controls are similar to HTML form elements: they include text fields, drop down lists, checkboxes, etc. These are some differences between HTML forms elements and XForms controls:

  • The value displayed by an XForms control comes from a node of the XForms instance. When you declare a control, you bind it to a node of your XForms instance with an XPath expression in the ref attribute. For instance this text field a text field is bound to the <number> element, which a child of <credit-card>:

    <xforms:input ref="/credit-card/number"/>
  • The way a control is rendered depends on model item properties that apply to the node the control is bound to: if it is bound to an invalid node then an error can be displayed; if the control is bound to a read-only node the value is displayed in read-only mode; if the node is not relevant the control isn't be displayed at all; if the control is bound to a non-existing node, the control is considered non-relevant and is not displayed;

The table below lists all the available XForms controls and shows for each one the XML you need to use in your view, as well as an example showing that control in action.

Control XForms in the view Example
Text field

<xforms:input ref="text"/>

xforms:input supports the following extension attributes:

  • xxforms:size: equivalent to the HTML size attribute
  • xxforms:maxlength: equivalent to the HTML maxlength attribute
  • xxforms:autocomplete: equivalent to the HTML autocomplete attribute
XForms Controls
Password field

<xforms:secret ref="secret"/>
XForms Controls
Text area

<xforms:textarea ref="textarea"/>

xforms:textarea supports the following extension attributes:

  • xxforms:rows: equivalent to the HTML rows attribute
  • xxforms:cols: equivalent to the HTML cols attribute
XForms Controls
Radio buttons

<xforms:select1 ref="carrier" appearance="full"><xforms:item><xforms:label>Fedex</xforms:label><xforms:value>fedex</xforms:value></xforms:item><xforms:item><xforms:label>UPS</xforms:label><xforms:value>ups</xforms:value></xforms:item></xforms:select1>
XForms Controls
Single-selection lists

<xforms:select1 ref="carrier" appearance="compact"><xforms:item><xforms:label>Fedex</xforms:label><xforms:value>fedex</xforms:value></xforms:item><xforms:item><xforms:label>UPS</xforms:label><xforms:value>ups</xforms:value></xforms:item></xforms:select1>
XForms Controls
Combo box

<xforms:select1 ref="payment" appearance="minimal"><xforms:item><xforms:label>Cash</xforms:label><xforms:value>cash</xforms:value></xforms:item><xforms:item><xforms:label>Credit</xforms:label><xforms:value>credit</xforms:value></xforms:item></xforms:select1>
XForms Controls
Autocomplete box

<xforms:select1 ref="name" selection="open" incremental="true" appearance="xxforms:autocomplete"><xforms:label class="label">Name:</xforms:label><xforms:itemset nodeset="instance('countries-name')/country"><xforms:label ref="name"/><xforms:value ref="name"/></xforms:itemset></xforms:select1>
Auto-Complete
Checkboxes

<xforms:select ref="wrapping" appearance="full"><xforms:choices><xforms:item><xforms:label>Hard-box</xforms:label><xforms:value>box</xforms:value></xforms:item><xforms:item><xforms:label>Gift</xforms:label><xforms:value>gift</xforms:value></xforms:item></xforms:choices></xforms:select>
XForms Controls
List

<xforms:select ref="taste" appearance="compact"><xforms:item><xforms:label>Vanilla</xforms:label><xforms:value>vanilla</xforms:value></xforms:item><xforms:item><xforms:label>Strawberry</xforms:label><xforms:value>strawberry</xforms:value></xforms:item></xforms:select>
XForms Controls
Trigger button

<xforms:trigger><xforms:label>Add carrier</xforms:label></xforms:trigger>
XForms Controls
Submit button

<xforms:submit submission="main-submission"><xforms:label>Submit</xforms:label></xforms:submit>
-
Submit link

<xforms:submit submission="main-submission" appearance="minimal"><xforms:label>Submit</xforms:label></xforms:submit>
-
Submit image

<xforms:submit submission="main-submission" appearance="minimal"><xforms:label><xhtml:img src="images/submit.gif" alt="Submit"/></xforms:label></xforms:submit>
-
Upload

<xforms:upload ref="files/file[1]"><xforms:filename ref="@filename"/><xforms:mediatype ref="@mediatype"/><xxforms:size ref="@size"/></xforms:upload>
Upload Control
Range

<xforms:range ref="range/value"><xforms:send submission="countries-submission" ev:event="xforms-value-changed"/></xforms:range>
XForms Controls

In the examples above, the labels and values for the select and select1 controls are declared in the control element with multiple <xforms:item> elements. Alternatively the label/value pairs can be pulled out from the instance. You do this with an <xforms:itemset> element (instead of <xforms:item> elements):

<xforms:select1 ref="country" appearance="compact"><xforms:itemset nodeset="instance('countries')/country"><xforms:label ref="name"/><xforms:value ref="us-code"/></xforms:itemset></xforms:select1>

4.2.2. Label, Alert, Help, and Hint

Nested inside each XForms control element, you can specify additional elements that can alter the way the control is displayed. The table below lists those elements:

Label

The label element is mandatory for all controls.

Alert

In each control you can specify an error message that can be displayed if the value entered by the user triggers a validation error.

<xforms:secret ref="secret"><xforms:alert>Invalid password</xforms:alert></xforms:secret>
Hint

You can specify a hint on each control, which shows up as a hint when users mouse over the control.

<xforms:textarea ref="textarea"><xforms:hint>Enter at least 11 characters</xforms:hint></xforms:textarea>
Help

If you specify a help message for a control, an icon with a question mark is displayed next to the control. When users click on the help icon, a dialog is displayed with the help message. The <xforms:help> can contain XHTML, or if you bind it to a node, the node can contain escaped XHTML.

<xforms:input ref="date" class="xforms-date"><xforms:label class="fixed-width">Birth date:</xforms:label><xforms:help><div><p>This field must contain:</p><ul><li>a valid date</li><li>which is at most one day in the future</li></ul></div></xforms:help></xforms:input>

The help dialog has a default with of 300px defined in xforms.js. To use a different width, override this default with:

.xforms-help-panel { width: 600px; }

By default, the help dialog will stretch vertically as needed so all the text in your help is visible. Then users can use the browser vertical scrollbar to navigate through the text. If instead you want the dialog to have a fixed height and scrollbars inside the dialog when the text doesn't fit that height, use CSS as in:

.xforms-help-panel .bd { height: 300px; overflow: auto; }

In the examples above, the text displayed is directly in the <xforms:label>, <xforms:alert>, <xforms:help>, or <xforms:hint> element. Alternatively that text can come from an XForms instance by using a ref attribute on any one of those elements. The ref references a node in the instant that contains the text to use. This is useful to externalize resources:

<xforms:secret ref="secret"><xforms:alert ref="@alert"/></xforms:secret>

Alternatively, you can nest xforms:output elements:

<xforms:secret ref="secret"><xforms:hint><xforms:output value="instance('resources')/help/secret"/></xforms:hint></xforms:secret>

With xforms:help and xforms:hint, you can also produce HTML, in two different ways:

  • By using literal XHTML under xforms:help or xforms:hint:

    <xforms:input ref="number"><xforms:label>Number</xforms:label><xforms:help><div><p>This field must contain one of the following values:</p><ul><li>One</li><li>Two</li><li>Three</li></ul></div></xforms:help></xforms:input>
    Note

    Elements in the XHTML namespace and in no namespace are supported.

  • By using a nested xforms:output with a text/html mediatype:

    <xforms:input ref="number"><xforms:label>Number</xforms:label><xforms:help><xforms:output mediatype="text/html" ref="instance('resources')/help/number"/></xforms:help></xforms:input>

    In this case, the node pointed to by the ref attribute must contain escaped HTML:

    <xforms:instance id="resources"><resources><help><number>&lt;div>&lt;p>This field must contain one of the following values:&lt;/p> &lt;ul>&lt;li>One&lt;/li> &lt;li>Two&lt;/li> &lt;li>Three&lt;/li>&lt;/ul>&lt;/div></number></help></resources></xforms:instance>

    If you want to have literal XHTML instead of escaped HTML in your resources, you can use the value attribute on xforms:output and the xxforms:serialize extension function:

    <xforms:input ref="number"><xforms:label>Number</xforms:label><xforms:help><xforms:output mediatype="text/html" value="xxforms:serialize(instance('resources')/help/number/*, 'html')"/></xforms:help></xforms:input>

    In this case, the resources instance contains:

    <xforms:instance id="resources"><resources><help><number><div><p>This field must contain one of the following values:</p><ul><li>One</li><li>Two</li><li>Three</li></ul></div></number></help></resources></xforms:instance>

You can mix and match literal XHTML and xforms:output

4.2.3. Upload

XForms allows you to upload files with the XForms Upload control:

<xforms:upload ref="files/file[1]"><xforms:filename ref="@filename"/><xforms:mediatype ref="@mediatype"/><xxforms:size ref="@size"/></xforms:upload>

The related section of the XForms model can look like this:

<xforms:instance id="my-instance"><files><file filename="" mediatype="" size=""/></files></xforms:instance><xforms:bind nodeset="file" type="xs:anyURI"/>

The file element is the element storing the result of the file upload. The result can be stored in two ways:

  • As a URL, by specifying the type xs:anyURI.
  • As Base64-encoded text, by specifying the type xs:base64Binary. Base64 is a mechanism to encode any binary data using a 65-character subset of US-ASCII. Using this mechanism allows embedding binary data into XML documents, at the typical cost of taking 50% more space than the original binary data. For more information, please refer to the RFC.

The optional xforms:filename, xforms:mediatype, and xxforms:size (the latter being an extension) allow storing metadata about an uploaded file:

  • xforms:filename: stores the file name sent by the user agent
  • xforms:mediatype: store the media type sent by the user agent
  • xxforms:size: stores the actual size in bytes of the uploaded data

Note that the file name and the media type are provided by the user agent (typically a web browser) and are not guaranteed to be correct.

The result of a file upload can look as follows when using xs:anyURI:

<file filename="photo.jpg" mediatype="image/jpeg" size="2345">file:/C:/Tomcat/temp/upload_00000005.tmp</file>
Note

The URL stored as the value of the upload is temporary and only valid until either:

  • the session expires,
  • the Java VM quits,
  • or a new file upload replaces the existing URI in the XForms instance.

The URL is only accessible from the server side, and will not be accessible from a client such as a web browser. It is not guaranteed to be a file: URL, only that it can be read with Orbeon Forms's URL generator.

The contents of the file can be retrieved using the URL Generator. The result will be an XML document containing a single root element containing the uploaded file in Base64-encoded text.

Note

Using the xs:anyURI type allows Orbeon Forms to make sure the uploaded file does not have to reside entirely in memory. This is the preferred method for uploading large files.

The result of a file upload can look as follows when using xs:base64Binary:

<file filename="photo.jpg" mediatype="image/jpeg" size="2345">/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAQDAwQDAwQEBAQFBQQFBwsHBwYGBw4KCggLEA4RERAO EA8SFBoWEhMYEw8QFh8XGBsbHR0dERYgIh8cIhocHRz/2wBDAQUFBQcGBw0HBw0cEhASHBwcHBwc ...</file>

In this case, the uploaded file is encoded an directly embedded into the XML instance. This is a good method to handle small files only, because the entire file is converted and stored in memory.

4.3. Repeating with xforms:repeat

4.3.1. Basics

A very common requirement of user interfaces consists in repeating visual elements, such as rows in a table or entries in a list. Those repeated sections usually have an homogeneous aspect: they all have the same or a very similar structure. For example, multiple table rows will differ only in the particular content they display in their cells. An example of this is an invoice made of lines with each a description, unit price, and quantity.

XForms provides a very powerful mechanism to implement such repeated structures: the xforms:repeat element. You use xforms:repeat around XHTML elements or XForms controls. For example, to repeat a table row, you write:

<xforms:repeat><xhtml:tr>...</xhtml:tr></xforms:repeat>

This is not enough to be functional code: you need to indicate to the xforms:repeat element how many repetitions must be performed. This is done not by supplying a simple count value, but by binding the the element to a node-set with the nodeset attribute. Consider the following XForms instance:

<xforms:instance id="employees-instance"><employees><employee><first-name>Alice</first-name></employee><employee><first-name>Bob</first-name></employee><employee><first-name>Marie</first-name></employee></employees></xforms:instance>

Assuming you want to produce one table row per employee, add the following nodeset attribute:

<xforms:repeat nodeset="instance('employees-instance')/employee"><xhtml:tr>...</xhtml:tr></xforms:repeat>

This produces automatically three xhtml:tr rows. Note that we explicitly use the XForms instance() function, but you may not have to do so if that instance is already in scope. Then you display in each row the content of the first-name element for each employee:

<xforms:repeat nodeset="instance('employees-instance')/employee"><xhtml:tr><xhtml:td><xforms:output ref="first-name"/></xhtml:td></xhtml:tr></xforms:repeat>

This works because for each iteration, the context node for the ref attribute changes: during the first iteration, the context node is the first employee element of the XForms instance; during the second iteration, the second employee element, and so on.

Note
The nodeset attribute of xforms:repeat must point to a so-called homogeneous collection. Such a collection must consist of contiguous XML elements with same name and same namespace. XForms does not predict what happens if the node-set is not homogenous.

4.3.2. Deleting Rows with the xforms:delete Action

xforms:repeat may be used purely for display purposes, but it can also be used for interactively editing repeated data. This includes allowing the user to delete and insert rows. Two XForms actions are used for this purpose: xforms:delete and xforms:insert.

xforms:delete is provided with a nodeset attribute pointing to the homogenous collection into which the insertion must take place. It also has an at attribute, which contains an XPath expression returning the index of the element to delete. See how xforms:delete is used in these 3 scenarios:

<!-- This deletes the last element of the collection --><xforms:delete nodeset="employees" at="last()"/><!-- This deletes the first element of the collection --><xforms:delete nodeset="employees" at="1"/><!-- This deletes the currently selected element of the collection (assuming the repeat id 'employee-repeat') --><xforms:delete nodeset="employees" at="index('employee-repeat')"/>

4.3.3. Inserting Rows with the xforms:insert Action

xforms:insert has a nodeset attribute pointing to the homogenous collection into which the insertion must take place. xforms:insert then considers the last element of that collection (and all its content if any) as a template for the new element to insert: it duplicates it and inserts it into the homogenous collection at a position you specify. The last element of an homogeneous collection therefore always acts as a template for insertions:

<!-- This inserts a copy of the template before the last element of the collection --><xforms:insert nodeset="employees" at="last()" position="before"/><!-- This inserts a copy of the template after the last element of the collection --><xforms:insert nodeset="employees" at="last()" position="after"/><!-- This inserts a copy of the template before the first element of the collection --><xforms:insert nodeset="employees" at="1" position="before"/><!-- This inserts a copy of the template after the first element of the collection --><xforms:insert nodeset="employees" at="1" position="after"/><xforms:insert nodeset="employees" at="last()" position="after"/><!-- This inserts a copy of the template before the currently selected element of the collection --><xforms:insert nodeset="employees" at="index('employee-repeat')" position="before"/><!-- This inserts a copy of the template after the currently selected element of the collection --><xforms:insert nodeset="employees" at="index('employee-repeat')" position="after"/>

The at attribute contains an XPath expression returning the index of the element before or after which the insertion must be performed. The position element contains either after or before, and specifies whether the insertion is performed before or after the element specified by the at attribute.

It is important to note that while it is possible to delete the last element of an homogeneous collection, it becomes then impossible to insert a new element into that collection with XForms 1.0, since there is no longer a template element available in this case (save for using an XML submission with replace="instance"). This means that in general you will want to have at least one element in your collections.

In case you want the user interface to visually appear empty empty when there is "no more" elements in the collection, you can use the tip provided below, which can be used in most situations. The idea is to consider that the last element of the collection is never displayed, but always used as a template for xforms:insert:

<xforms:instance id="employees-instance"><employees><employee><first-name>Alice</first-name></employee><employee><first-name>Bob</first-name></employee><employee><first-name>Marie</first-name></employee><!-- This is a template used by xforms:insert --><employee><first-name/></employee></employees></xforms:instance>

You do not want to display that template, however. Therefore you use an xforms:repeat element of the form:

<xforms:repeat nodeset="instance('employees-instance')/employee[position() &lt; last()]">...</xforms:repeat>

The position() &lt; last() condition tells xforms:repeat to consider all the elements of the collection except the last one. This causes the repetition to display zero iteration when there is one element in the collection, one iteration when there are two, etc. The xforms:insert action, on the other hand, operates on the entire collection including the last element, so that that element can be duplicated:

<xforms:insert nodeset="employees" at="..." position="..."/>

Another solution involves using an xforms:bind element which makes the last element of the collection non-relevant. This achieves the same result, but requires extra code, so the tip above is usually preferred.

Upon submission, some care must be taken with repeat template. For example, if the first-name element above is required, and the template contains an empty value as above, submission will fail. xforsm:bind statements must then also exclude the last element of the collection:

<xforms:bind nodeset="employee[position() &lt; last()]/first-name" required="true()"/>
Note

If you are dealing with an XML document format which requires removing the last element of a collection, you have to post-process your XForms instance to remove such extra elements, and pre-process it to add such elements when initializing your XForms instance.

4.3.4. Using xforms:trigger to Execute Actions

Insertions and deletions are typically performed when the user of the application presses a button, with the effect of adding a new repeated element before or after the currently selected element, or of deleting the currently selected element. You use an xforms:trigger control and the XPath index() function for that purpose:

<xforms:trigger><xforms:label>Add</xforms:label><xforms:action ev:event="DOMActivate"><xforms:insert nodeset="employees" at="index('employee-repeat')" position="after"/></xforms:action></xforms:trigger>

or:

<xforms:trigger><xforms:label>Delete</xforms:label><xforms:action ev:event="DOMActivate"><xforms:delete nodeset="employees" at="index('employee-repeat')"/></xforms:action></xforms:trigger>

Note that we use xforms:action as a container for xforms:insert and xforms:delete. Since there is only one action to execute, xforms:action is not necessary, but it may increase the legibility of the code. It is also possible to write:

<xforms:trigger><xforms:label>Add</xforms:label><xforms:insert ev:event="DOMActivate" nodeset="employees" at="index('employee-repeat')" position="after"/></xforms:trigger>

or:

<xforms:trigger><xforms:label>Delete</xforms:label><xforms:delete ev:event="DOMActivate" nodeset="employees" at="index('employee-repeat')"/></xforms:trigger>

Notice in that case how ev:event="DOMActivate" has been moved from the enclosing xforms:action to the xforms:insert and xforms:delete elements.

4.3.5. Nested Repeats

It is often desirable to nest repeat sections. Consider the following XForms instance representing a company containing departments, each containing a number of employees:

<xforms:instance id="departments"><departments><department><name>Research and Development</name><employees><employee><first-name>John</first-name></employee><employee><first-name>Mary</first-name></employee></employees></department><department><name>Support</name><employees><employee><first-name>Anne</first-name></employee><employee><first-name>Mark</first-name></employee><employee><first-name>Sophie</first-name></employee></employees></department></departments></xforms:instance>

This document clearly contains two nested sections subject to repetition:

  • Departments: a node-set containing all the department elements can be referred to with the following XPath expression: instance('departments')/department.

  • Employees: a node-set containing all the employee elements can be referred to with the following XPath expression: instance('departments')/department/employees/employee. However, if the context node of the XPath expression points to a particular department element, then the following relative XPath expression refers to all the employee elements under that department element: employees/employee.

Following the example above, here is how departments and employees can be represented in nested tables with XForms:

<xhtml:table><xforms:repeat nodeset="instance('departments')/department"><xhtml:tr><xhtml:td><xforms:output ref="name"/></xhtml:td><xhtml:td><xhtml:table><xforms:repeat nodeset="employees/employee"><xhtml:tr><xhtml:td><xforms:output ref="first-name"/></xhtml:td></xhtml:tr></xforms:repeat></xhtml:table></xhtml:td></xhtml:tr></xforms:repeat></xhtml:table>

In the code above, the second xforms:repeat's nodeset expression is interpreted relatively to the department element of the parent xforms:repeat for each iteration of the parent's repetition. During the first iteration of the parent, the "Research and Development" department is in scope, and employees/employee refers to the two employees of that department, John and Mary. During the second iteration of the parent, the "Support" department is in scope, and employees/employee refers to the three employees of that department, Anne, Mark and Sophie.

4.4. Events

4.4.1. Introduction

[TODO: Introduction to events in XForms.]

4.4.2. Using the ev:observer Attribute

The ev:observer attribute, defined by the XML Events specification, allows you to register event handlers by specifying an element identifier, instead of embedding the event handler within that element. This is particularly useful to register event handlers on <xforms:instance> elements, which do not allow you to directly embed XML event handlers. The current support is limited to adding the ev:observer attribute on XForms actions under <xforms:model> with the ev:observer attribute referring to a child <xforms:instance>.

<xforms:model id="main-model"><!-- Child instance --><xforms:instance id="child-instance" src="my-instance.xml"/><!-- Register the event handler on the child instance --><xforms:dispatch ev:observer="child-instance" ev:event="xforms-insert" target="main-model" name="update-after-insert"/></xforms:model>

Note that you still need to use the ev:event attribute to specify to what event the handler responds.

4.5. Actions

4.5.1. Setting Instance Values with the xforms:setvalue Action

There are two ways of providing the value to set with <xforms:setvalue>. The first one specifies the value as a literal enclosed in the <xforms:setvalue> element. The second possibility uses the value attribute: the content of the attribute is an XPath expression evaluated in the context of the node the xforms:setvalue element is bound (through the ref attribute). The content of the node pointed to by the ref attribute will be set with the result of the XPath expression provided in the value attribute. The example below and uses two <xforms:setvalue>, each one providing the new value in a different way.

<xforms:trigger><xforms:label>Submit</xforms:label><xforms:action ev:event="DOMActivate"><xforms:setvalue ref="clicked">my-button</xforms:setvalue><xforms:setvalue ref="flavor" value="concat('van', 'illa')"/></xforms:action></xforms:trigger>

4.5.2. Displaying Messages with the xforms:message Action

The XForms message action displays a message to the user.

Typically, the content of the message element is the message to render. It can also come from the binding attributes (ref or bind), or from the linking attribute (src). The order of preference is the following:

  • Binding attributes
  • Linking attribute
  • Inline text
Note
  • The only value currently supported for the level attribute is modal. This attribute is optional.
  • When using the linking attribute (src), the value must be an absolute URL, starting with oxf:, http: or other supported protocols.
<xforms:trigger><xforms:label>Test</xforms:label><xforms:message ev:event="DOMActivate" ref="taste"/></xforms:trigger>

4.6. Submission

Two properties control some aspects of XForms submission in Orbeon Forms:

<property as="xs:boolean" name="oxf.xforms.optimize-post-all" value="true"/>

If set to true (the default), Orbeon Forms optimizes submissions with replace="all" by sending the response of the submission directly to the web browser. This however means that submission errors cannot be caught by XForms event handlers after Orbeon Forms has started connecting to the submission URL, as should be the case following XForms 1.0. If set to false, Orbeon Forms buffers the reply so that errors can be handled as per XForms 1.0. However, this solution is less efficient.

<property as="xs:boolean" name="oxf.xforms.optimize-local-submission" value="true"/>
  • If set to true (the default), Orbeon Forms optimizes "local" HTTP and HTTPS submissions, i.e. submissions performed to a URL controlled by Orbeon Forms itself, by directly submitting using the Java Servlet API instead of actually using the HTTP protocol for the submission.
  • If set to false, Orbeon Forms always always uses the HTTP or HTTPS protocol, which is less efficient. In this case, it is possible to specify the xxforms:post method instead of the post method on the xforms:submission element to force an optimized local submission.

5. XPath Expressions in XForms

5.1. Note About XPath 2.0 Expressions

Orbeon Forms uses XPath 2.0 expressions instead of XPath 1.0 expressions as mandated by XForms 1.0 and XForms 1.1. This allows much greater flexibility in the expressions you can use in Orbeon Forms (and once you have tasted XPath 2.0, you can't go back to XPath 1.0!).

In general, this does not cause incompatibilities: most XPath 1.0 expressions work without issues with an XPath 2.0 implementation. But one place where there is an incompatibility is the use of the XPath 1.0 if() function. This function clashes with XPath 2.0's built-in if() construct. The bottom line is that you cannot directly use the XForms 1.0 if() function in Orbeon Forms at the moment. The following, for example, will not work in Orbeon Forms:

if (normalize-space(/first-name) = '', '', concat('Hello, ', /first-name, '!'))

But you have workarounds:

  • Use the XPath 2.0 if (...) then ... else ... construct instead:

    if (normalize-space(/first-name) = '') then '' else concat('Hello, ', /first-name, '!')
  • Use the Orbeon Forms xxforms:if() extension, which behaves like the XForms 1.0 if() function:

    xxforms:if (normalize-space(/first-name) = '', '', concat('Hello, ', /first-name, '!'))

6. XForms Instance Initialization

6.1. Rationale

An XForms page usually needs to contain initial data when first loaded. The data may be inline, come from a database, from a form submitted on a previous page, etc. This section looks at the different ways to initialize XForms instances.

6.2. Initializing XForms Instances from the PFC

6.2.1. Page Flow Definitions

The Page Flow Controller supports an MVC architecture that allows pages to be built with a page model and a page view. The page model is in charge of preparing data then sent to the page view for display. Assume the following definitions in your page flow, with a page model and either a static page view:

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

Or a dynamic XSLT page view:

<page id="..." path-info="..." model="my-page-model.xpl" view="my-page-view.xsl"/>

As always with Orbeon Forms, the page model produces a page model document on its data output, and the page view can access this document on its data input, as shown in the following sections. The page view also has access on its instance input to the current XML submission, which may be an unmodified submission performed on the page (in case the page model doesn't have an instance output), or a submission created or modified by the page model and produced on its instance output. These mechanisms are described in details in the PFC documentation.

6.2.2. Using the src Attribute

The <xforms:instance> element supports an src attribute, able to access the current XML submission using the input:instance URI, as well as the page model data using the input:data URI.

<html><head><title>Summary</title><xforms:model><xforms:instance id="document-infos-instance" src="input:instance"/>...</xforms:model></head><body>...</body></html>

6.2.3. Using XInclude

In this scenario, the PFC page model generates an XML document which contains an XForms instance on its data output. A static PFC page view then includes this document using xi:include, as follows:

<html><head><title>Summary</title><xforms:model><xforms:instance id="document-infos-instance"><!-- This is where the XML document produced by the page model is included --><xi:include href="input:data"/></xforms:instance>...</xforms:model></head><body>...</body></html>

The use of the URI input:data instructs XInclude processing to dynamically include the data output of the page view, which is produced on the data output of the page model. Note that you can also use the instance input, which then refers to the current XML submission:

<xforms:instance id="document-infos-instance"><!-- This is where the XML document produced by the page model is included --><xi:include href="input:instance"/></xforms:instance>
Note

Whenever possible, the use of the <xforms:instance>'s src attribute is preferable. Doing so may have a positive impact on performance as more caching can take place.

6.2.4. Using XSLT

You can use a dynamic XSLT page view to perform the inclusion of the instance. XSLT is more flexible than XInclude, but less efficient at runtime. The following example uses the data input of the page view to initialize an XForms instance:

<html xsl:version="2.0"><head><title>Summary</title><xforms:model><xforms:instance id="document-infos-instance"><!-- This is where the XML document produced by the page model is included --><xsl:copy-of select="/*"/></xforms:instance>...</xforms:model></head><body>...</body></html>

Note the use of xsl:version="2.0" on the root element of the document, which instructs the PFC to process the page view as an XSLT stylesheet.

The following example uses instead the instance input of the page view to initialize an XForms instance:

<xforms:instance id="document-infos-instance"><!-- This is where the XML document produced by the page model is included --><xsl:copy-of select="doc('input:instance')"/></xforms:instance>

The use of the XPath doc() function with a URI input:instance instructs XSLT processing to dynamically include the instance input of the page view.

Note
You can use XInclude instructions in a dynamic XSLT page view as well. In this case, it is important to note that XInclude instructions are processed before XSLT instructions, i.e. the result of XInclude instructions is an XSLT stylesheet, which is then executed.
Note

Whenever possible, the use of the <xforms:instance>'s src attribute is preferable. Doing so may have a positive impact on performance as more caching can take place. For performance reasons, we also recommend using static XHTML views instead of XSLT whenever possible.

6.3. Initializing XForms Instances with an XForms Submission

[TODO]

7. URLs in XForms

7.1. Rationale

XForms documents can refer to external resources using URIs in the following circumstances:

  • External Instances. The xforms:instance element can have an src attribute linking to an external instance definition.

  • Submission. The xforms:submission element must refer to an action URI.

  • Load Action. The xforms:load action must refer to an URI that must be loaded upon execution.

  • Image Mediatype. The xforms:output control may refer to an image URI.

  • Message, Label, Help, Hint, and Alert. xforms:label, xforms:help, xforms:hint, and xforms:alert may use an src attribute to refer to external content.

    Note
    The XForms 1.1 draft of November 15, 2004 removes linking attributes from actions and metadata elements and "the src attribute is not available to XForms 1.1 message, label, help, hint, alert elements."

URIs are resolved relatively to a base URI. The base URI is, by default, the external URL used to display the XForms page, with special handling of the servlet context, if necessary. It is also possible to override this behavior by adding xml:base attributes on xforms:load or any of its ancestor elements.

7.2. External XForms Instances

Referring to external XForms instances is done with the src attribute on the xforms:instance element:

<xforms:instance src="instance.xml"/>

This feature allows for improved modularity by separating an XForms instance definition from an XHTML page. It also allows for producing XForms instances dynamically.

The following assumes that Orbeon Forms runs in the /ops servlet context:

Base URI
(External URL or xml:base attributes)
Initial URI
(src attribute)
Resolved URI Comment

The following URI is loaded in a servlet:

http://a.org/ops/page

http://b.com/instance http://b.com/instance Absolute URLs are left untouched.
/new-instance http://a.org/ops/new-instance Absolute paths resolve against the current servlet context.
admin/instance http://a.org/ops/admin/instance The relative path resolves against the original URL.

The following path is loaded in a portlet:

/example/page

http://b.com/instance http://b.com/instance Absolute URLs are left untouched.
/new-instance /new-instance The absolute path is used as is. The XForms instance is loaded from the portlet. The developer must make sure that the path resolves to a PFC entry producing XML.
admin/instance /example/admin/instance The relative path is resolved against the original path. The XForms instance is loaded from the portlet. The developer must make sure that the path resolves to a PFC entry producing XML.

7.3. XForms Submisssion

Specifying a submission URL is done with the action attribute on the xforms:submission element:

<xforms:submission action="/submission" ref="..."/>

The following assumes that Orbeon Forms runs in the /ops servlet context:

Base URI
(External URL or xml:base attributes)
Initial URI
(action attribute)
XForms Init 1 Resolved URI Comment

The following URI is loaded in a servlet:

http://a.org/ops/page

http://b.com/submission N/A http://b.com/submission The absolute URL is left untouched. The XForms submission is performed on the absolute URL.
/new-submission N/A http://a.org/ops/new-submission Absolute paths resolve against the current servlet context.
admin/submission N/A http://a.org/ops/admin/submission The relative path resolves against the original URL.

The following path is loaded in a portlet:

/example/page

http://b.com/submission N/A http://b.com/submission The absolute URL is left untouched. The XForms submission is performed on the absolute URL.
/new-submission Yes /new-submission The absolute path is used as is. The XForms submission is performed on the portlet.
No http://a.org/ops/new-submission The absolute path resolves against the current servlet context. The submission is performed on the web application.
admin/submission Yes /example/admin/submission The relative path is resolved against the original path. The XForms submission is performed on the portlet.
No http://a.org/ops/ example/admin/submission The relative path resolves against the original path, then against the the current servlet context. The submission is performed on the web application.

1 If "yes", this means the submission is performed during XForms initialization, for example upon an xforms-ready event. If "no", this means that the submission is performed after XForms initialization, for example upon the user activating a trigger.

7.4. XForms Load Action

The xforms:load action can refer to a resource to load either through the resource attribute or using a single-node binding retrieving the URI from an XForms instance. In both cases, the value of the URI is resolved relatively to the base URI.

The following assumes that Orbeon Forms runs in the /ops servlet context:

Base URI
(External URL or xml:base attributes)
Initial URI
(resource or Single-Node Binding)
show
f:url-type
Resolved URI Comment

The following URI is loaded in a servlet:

http://a.org/c/d

http://b.com/e/ replace http://b.com/e/ The absolute URL is left untouched. The new page replaces the existing page.
new The absolute URL is left untouched. A new window or tab opens for the new page.
/f replace http://a.org/c/f Absolute paths resolve against the current servlet context. The new page replaces the existing page.
new Absolute paths resolve against the current servlet context. A new window or tab opens for the new page.
g replace http://a.org/c/g The new page replaces the existing page.
new A new window or tab opens for the new page.

The following path is loaded in a portlet:

h/d

http://b.com/e/ replace http://b.com/e/ This causes the application to load a page outside of the portlet, replacing the entire portal.
new This causes the application to load a page in a new window outside of the portlet.
/f replace /f The resulting path is loaded within the portlet.
replace
f:url-type= "resource"
http://a.org/c/f The resulting path is loaded in the same window outside the portal.
new http://a.org/c/f The resulting path is loaded in a new window.
g replace h/g The resulting path is loaded within the portlet.
replace
f:url-type= "resource"
undefined undefined
new undefined undefined

7.5. Image Mediatype for xforms:output

When an xforms:output control refers to an image URI, as documented below, the resulting value is resolved relatively to the base URI.

8. XForms and Services

8.1. Introduction

XForms 1.0 allows an XForms page to perform submissions of XForms instances and to handle a response. In most cases, both the submitted XForms instance and the response are XML documents.

Note
It is possible to submit an XForms instance with the HTTP GET method. In that case, some information contained in the XML document is lost, as the structure of the instance, attributes, and namespace prefixes among others, are not passed to the submission.

The XForms submission feature practically allows forms to call XML services. Those services are accessible through an XML API, which means that a request is performed by sending an XML document to the service, and a response consists of an XML document as well.