eXforms - extending XForms 1.0

14 December 2006

This version:
http://exforms.org/all.html
Editor:
David Landwehr, exforms.org

Status of this Document

This document describes how to extend an XForms processor.

Table of Contents

1 Extension mechanism
    1.1 The exf:requiredModules Element
    1.2 Modules in this specification
2 Template Extension
    2.1 The Module
    2.2 The exf:template Attribute
    2.3 The exf:template() Function
    2.4 The exf:template-owner() Function
    2.5 The exf:template-assign Action
3 Conditional, Looping and Invocation Extension for Actions
    3.1 The Module
    3.2 The exf:if Attribute
    3.3 The exf:while Attribute
    3.4 The exf:iterateAttribute
    3.5 The exf:invoke and exf:invoke-initial Attribute
4 Model Item Properties Extension
    4.1 The Module
    4.2 The exf:relevant() Function
    4.3 The exf:readonly() Function
    4.4 The exf:required() Function
5 Variable
    5.1 The Module
    5.2 The exf:variable Element
6 Sorting
    6.1 The Module
    6.2 The exf:sort Element
    6.3 The exf:sort Function
7 References
    7.1 Normative References

Appendix

A Acknowledgments (Non-Normative)


1 Extension mechanism

The [XForms 1.0] includes a mechanism to extend forms in a compliant way by using the mustUnderstand attribute. This specification uses this mechanism to extend forms with additional functionality in a conforming way by requiring an XForms processor to understand the exf:requiredModules element.

1.1 The exf:requiredModules Element

The exf:requiredModules element is used to create compliant forms by combining the element with the mustUnderstand element from [XForms 1.0].

Attributes:

modules

Required attribute of type xsd:list of xsd:QName specifying the extensions the model or page requires.

The extension mechanism works in the following way:

  • The exf:requiredModules must be included in an xforms:extension element. An author must specify the attribute xforms:mustUnderstand with the value true to ensure the processor will terminate processing if it does not support that element.

  • The modules attributes specifies the modules that the particular model or page requires to run the form. A module is defined by this specification for each extension as a QName.

  • If the exf:requiredModules element was specified in an xforms:extension element which is a descendant of a model then the processor is must disable that particular model when it is unable to process the required modules by disabling all form controls bound to that model. A processor may also terminate processing instead of disabling the model.

  • If the exf:requiredModules element was specified in an xforms:extension element outside of a model then the processor must understand all modules required. If a processor hasn't support for all required modules it must terminate processing.

Example: Example for how to use the exf:requiredModules
<xforms:model>
  <xforms:instance src="external.xml"/>
  <xforms:extension>
    <exf:requiredModules modules="" xforms:mustUnderstand="true"/>
  </xforms:extension>
</xforms:model>

1.2 Modules in this specification

QNameReference
exf:template2 Template Extension
exf:conloop3 Conditional, Looping and Invocation Extension for Actions
exf:mips4 Model Item Properties Extension
exf:variable5 Variable
exf:sorting6 Sorting
exf:allStates that all modules are required.

2 Template Extension

2.1 The Module

This module defines a way of associating a DOM fragment to a node and a way of accessing the fragment. The use case is that an author can store information which isn't directly dependent to the instance data but is required for creating a user interface. An example could be an instance representing a mail box and the author want to store a valid from the UI whether a mail was selected. This selected state would then be defined in the template.

The module name to be used for this extension is defined as exf:template

Note:

Using templates in model item properties is undefined, since this module does not state the order for assigning the templates.

2.2 The exf:template Attribute

The exf:template must be placed on a xforms:bind element and it must be a [XPath 1.0] expression selecting a node-set. The first node in document order from this node-set is used to create the template. The assignment of templates to instance nodes happens during the rebuild processing in the following way:

  1. Every node from the xforms:bind element's context is selected for template assignment

  2. If a selected node hasn't got a template then the exf:template is evaluated to locate its template. If the template evaluates to a non-empty node-set then the first node in document order from the node-set is cloned and assigned to the instance node as its template.

Note:

Notice that assignments of templates is preserved across rebuilds. This ensures that information isn't dropped between rebuilds.

Example: how exf:template is used
<xforms:model>
  <xforms:instance id="default">
    <emailbox xmlns="">
      <email from="contact@exforms.org" subject="How to..."/>
      <email from="spam@spammer.com" subject="Buy this for free"/>
  </xforms:instance>
  <xforms:instance id="template">
    <template xmlns="">
      <selected>false</selected>
    </template>
  </xforms:instance>
  <xforms:bind nodeset="email" exf:template="instance('template')"/>
</xforms:model>

2.3 The exf:template() Function

node-set exf:template(node-set?)

The exf:template-owner returns the template owner for the current context node. If the context node is in a template then the function returns the empty node-set.

Example:
<xforms:repeat nodeset="email">
  <xforms:input ref="exf:template()/selected">
    <xforms:label>Selected?</xforms:label>
    <xforms:setvalue ref="ext:template-owner()" value="true" ev:event="click"/>
  </xforms:input>
</xforms:repeat>

See Example in 2.2 The exf:template Attribute for the model

2.4 The exf:template-owner() Function

node-set exf:template-owner()

The exf:template-owner returns the template owner for the current context node. If the context node is in a template then the function returns the empty node-set.

Example: how to use the exf:template-owner()
<xforms:repeat nodeset="email">
  <xforms:input ref="exf:template()/selected">
    <xforms:label>Selected?</xforms:label>
    <xforms:setvalue ref="ext:template-owner()" value="true" ev:event="click"/>
  </xforms:input>
</xforms:repeat>

See Example in 2.2 The exf:template Attribute for the model

2.5 The exf:template-assign Action

This action (re-)associates or removes a template.

Common Attributes: Must have a single-node binding (defined in XForms).

Attributes:

Special Attributes:

template

Optional [XPath 1.0] node-set expression to select the node to use for the template.

The processing for exf:template-assign is as follows:

  1. The single-node binding is evaluated to determine which node should be processed

  2. If the attribute template is omitted then the node's associated template is dropped. If the node has no template this action has no effect.

    otherwise

    template is evaluated and if it selects a node-set then the first node in document order from that node-set is cloned and associated as a template. If the node-set was empty then any associated template is removed. If the evaluation produced anything but a node-set then this action has no effect.

Example: how to use the ext:template-assign Action
<xforms:trigger>
  <xforms:label>Make additional selected for the first &lt;email> in template</xforms:label>
  <xforms:action ev:event="DOMActivate">
    <xforms:insert nodeset="instance('template')/selected" at="1" position="after"/>
    <exf:template-assign ref="email" template="instance('template')"/>
  </xforms:action>
</xforms:trigger>

See Example in 2.2 The exf:template Attribute for the model

3 Conditional, Looping and Invocation Extension for Actions

3.1 The Module

This module defines a set of attributes which can be used on all action to make conditional and looping behavior of the action when invoked. The following is what this modules provides:

Iterate the invocation of the action over a node-set
Condition determine if an action should be invoked
Loop the action as long a condition holds true
Invoke an action if a XPath expression signals true. An XPath expression signals true if it boolean state changes from false to true during a xforms-refresh

The attributes defined by this specification has a precedence order which is defined as following:

  1. exf:if conditional attribute

  2. exf:while looping attribute

  3. exf:iterate iterating attribute

The last attributes are called exf:invoke and exf:invoke-initial but has no precedence since these attributes are a triggering mechanism.

Special handling for deferred updates apply for exf:while and exf:iterate so that the entire execution happens in one deferred update's scope. This means that the processing model must not dispatch the xforms-rebuild, xforms-recalculate, xforms-revalidate and xforms-refresh. However it is allowed for the author to explicitly use one of the actions to perform the task if desired.

Note:

Notice that exf:iterate changes the context for the expressions.

The module name to be used for this extension is defined as exf:conloop

3.2 The exf:if Attribute

The exf:if is an [XPath 1.0] expression which is evaluated before an action is executed. The expressions result is converted to a boolean as if converted with the boolean() defined by the [XPath 1.0] specification and if it evaluates to false the action's must not be executed.

Example: how to use exf:if
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node selected="false"/>
      <node selected="true"/>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:trigger>
  <xforms:label>Delete the first node if it is selected</xforms:label>
  <xforms:delete nodeset="node" at="1" exf:if="./@selected='true'"/>
</xforms:trigger>

Notice the evaluation scope for the exf:if attribute. It uses the in-scope evaluation context.

3.3 The exf:while Attribute

The exf:whileel> is an [XPath 1.0] expression which is evaluated to a boolean by converting the result as by the boolean() defined by the [XPath 1.0] specification. The attribute is evaluated before the initial execution of the action and if it is true the action is executed. Afterwards it is evaluated again and if it is still true the action is executed once more and so on.

Note:

Notice that the exf:if is evaluated after exf:while is evaluated

Example: how to use exf:while
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node selected="true"/>
      <node selected="true"/>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:trigger>
  <xforms:label>Delete all selected</xforms:label>
  <xforms:delete nodeset="node" at="1" exf:while="../node/@selected='true'"/>
</xforms:trigger>

Notice the evaluation scope for the exf:while attribute. It uses the in-scope evaluation context.

3.4 The exf:iterateAttribute

The exf:iterate is an [XPath 1.0] expression which must evaluate to a node-set. The action is executed with each node in the node-set as context. This context replaces the default context set by the [XForms 1.0].

Note:

Notice that the exf:iterate changes the context for exf:if and exf:while. Also notice the exf:iterate is evaluated before any of the two.

Example: how to use exf:iterate
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node selected="true"/>
      <node selected="true"/>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:trigger>
  <xforms:label>Delete all selected</xforms:label>
  <xforms:delete nodeset="." at="1" exf:iterate="node[@selected='true']"/>
</xforms:trigger>

Notice the evaluation scope for the delete action

3.5 The exf:invoke and exf:invoke-initial Attribute

The exf:invoke is an [XPath 1.0] expression which is converted to a boolean as by the boolean() from the [XPath 1.0] specification. The expression is evaluated during xforms-refresh as if the expression was a binding expression and if it evaluates from false to true then the action it is placed on is executed.

A helper attribute for exf:invoke is exf:invoke-initial which is of type xsd:boolean. This attribute sets the initial state such that this functionality works initially. If this helper attribute isn't present on the action the initial state is set to true.

Example: how to use exf:invoke
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node1>value</node1>
      <node2></node2>
    </data>
  </xforms:instance>
  <!-- Calculate how many times node1's value is set to value -->
  <xforms:setvalue ref="node2" value=".+1" exf:invoke="../node1 = 'value' exf:inoke-initial="false"/>

4 Model Item Properties Extension

4.1 The Module

This modules defines a set of [XPath 1.0] functions to access the model item property states of a node in a instance. The following is the model item properties from the [XForms 1.0] that can be accessed:

readonly true if the node or one of its anscestors has a readonly model item property which computes to true.
relevant false if the node or one of its anscestors has a relevant model item property which computes to false.
required true if the node has required model item property which computes to true.

When a processor implements this extensions it must include the states as dependencies in the master dependency graph when calculating dependent nodes. This means that e.g. a calculate expression must be marked for recalculation when a node has a state change which the expression was dependent on.

It is possible to create circular dependencies using the functions defined in this module. If during the rebuild a circular dependency is detected then processing must termined as defined by the XForms specification.

The module name to be used for is defined as exf:mip.

4.2 The exf:relevant() Function

boolean exf:relevant(node-set?)

The exf:relevant() returns the relevant state of the node from the node-set which is first in document order. If the node-set is empty then the function returns false. If the argument is omitted, it defaults to a node-set with the context node as its only member.

Example: how to use exf:relevant()
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node1/>
      <node2/>
    </data>
  </xforms:instance>
  <!-- data1 is relevant if data2 is-->
  <xforms:bind nodeset="data1" relevant="exf:relevant(../data2)"/>

4.3 The exf:readonly() Function

boolean exf:readonly(node-set?)

The exf:readonly() returns the readonly state of the node from the node-set which is first in document order. If the node-set is empty then the function returns false. If the argument is omitted, it defaults to a node-set with the context node as its only member.

Example: how to use exf:readonly()
<xforms:model>
  <xforms:instance>
    <data xmlns="" readonly="false">Data</data>
  </xforms:instance>
  <xforms:bind nodeset="text()" required="not(exf:readonly())" readonly="../@readonly="false"/>

4.4 The exf:required() Function

boolean exf:required(node-set?)

The exf:required() returns the required state of the node from the node-set which is first in document order. If the node-set is empty then the function returns false. If the argument is omitted, it defaults to a node-set with the context node as its only member.

Example: how to use exf:required()
<xforms:model>
  <xforms:instance>
    <data xmlns="" required="false">Data</data>
  </xforms:instance>
  <xforms:bind nodeset="." required="boolean-from-string(@required)"/>
</xforms:model>
...
<xforms:value output="concat('element required is ', exf:required(/data))"/>

5 Variable

5.1 The Module

This module defines an element which enables the use of variables in XPath expressions ([XPath 1.0]).

The module name to be used for this extension is defined as exf:variable

5.2 The exf:variable Element

The exf:variable element introduces a variable to be used in XPath expression in the subtree of the parent to the exf:variable element.

Attributes

name

Required The name of the variable. This is a xsd:QName.

select

Required [XPath 1.0] expression which is the value assigned to the variable. The expression is evaluated in the context defined by [XForms 1.0] and by the model attribute on this element.

model

Optional The xforms model used for scoping which model the attribute correspons to.

For exf:variables in the model they are updated before the processing of the xforms-recalculate event and for exf:variable elements in the UI they are updated before the xforms-refresh event. A variable scope is defined in a model and from the parent of the exf:variable element and the last one with the same name takes precedens. It must be possible to defined identical named variables for different model in the same document scope.

Example: how to use exf:variable in the UI
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <a><b><c>value</c></b></a>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:group>
  <exf:variable name="bvalue" select="a/b"/>
  
  The c value: <xforms:output ref="$bvalue/c"/>
</xforms:group>

Evaluates the binding to be the c node.

Example: how to use exf:variable in the model
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <a><b><c>value</c></b></a>
    </data>
  </xforms:instance>

  <exf:variable name="bnode" select="a/b"/>
  <exf:variable name="boolean" select="$bnode/c = 'value"/>

  <xforms:bind nodeset="$b" relevant="$boolean"/>
</xforms:model>

Uses a variable in a exf:variable element and in the relevant

6 Sorting

6.1 The Module

This module provides an element and XPath functions for sorting XPath node-sets.

6.2 The exf:sort Element

The sort elements are placed as the first children under a XForms element which contains a node-set binding. The first sort element specifies the primary sorting and only if two nodes are equal the secondary sort element will be used and so on. If two nodes are said to be equal and there are no more sort elements to specify their internal order then the order of the two nodes are the document node order.

Attributes:

select

Required [XPath 1.0] expression evaluation to the value which is used for sorting. The evaluation scope for this attribute is the one set by the nodeset attribute.

lang

Optional specifies the locale of the sorting keys. If the attribute is absent the a system default is used.

data-type

Optional one of text, number or a qname-but-not-ncname. The default is text.

order

Optional one of ascending or descending. Specifies the sorting order where ascending specifies ascending order and descending specifies descending order. If absent then ascending is the default value.

case-order

Optional one of lower-first or upper-first. If lower-first then lower case characters are before upper-case characters. This attribute applies only when data-type="text". If absent upper-first is the default value.

Example: how to use exf:sort
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node value="2">Node 1</node>
      <node value="1">Node 2</node>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:repeat nodeset="node">
  <exf:sort select="@value" data-type="number"/>
  <xforms:output ref="."/>
</xforms:repeat>

Will output Node 2 then Node 1

Example: how to use exf:sort to reverse document order
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node value="2">Node 1</node>
      <node value="1">Node 2</node>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:repeat nodeset="node">
  <exf:sort select="position()" data-type="number" order="descending"/>
  <xforms:output ref="."/>
</xforms:repeat>

Will reverse the document order

Example: how to use exf:sort in select1
<xforms:model>
  <xforms:instance>
    <addressbook xmlns="">
      <person>
        <name>Smidth, John</name>
        <street>204 Street</street>
        <age>21</age>
      </person>
      <person>
        <name>Smidth, Alice</name>
        <street>204 Street</street>
        <age>23</age>
      </person>
      <person>
        <name>Seins, Jon</name>
        <street>202 Street</street>
        <age>18</age>
      </person>
      <selected/>
    </addressbook>
  </xforms:instance>
</xforms:model>

<xforms:select1 ref="selected">
  <xforms:label>Selected person:</xforms:label>
  <xforms:itemset nodeset="/addressbook/person">
    <exf:sort select="street"/>
    <exf:sort select="age"/>
    <exf:sort select="name"/>
    
    <xforms:label ref="name"/>
    <xforms:copy ref="."/>
  </xforms:itemset>
</xforms:select1>

Sorts the itemset in the select1 in the order street, age, name

6.3 The exf:sort Function

node-set exf:sort(node-set, string, string?, string?, string?)

The exf:sort function sorts a node-set provided as the first argument using an XPath expression given as the second argument. The sorting expression evaluates to a string which is used as a XPath expression created with the same context as created the expression containing the exf:sort function. The third argument specifies the data-type of the sorting expression (one of number or text anything but one of these two values will default the value to text), e.g. if it should evaluate to a number or string. The fourth argument specifies the ordering of the sorting (one of ascending of descending anything but one of these two values will default the value to ascending. The fifth element is used when the data-type was text to specify the case order. The argument should be one of lower-first or upper-first anything but one of these two values will default the argument to lower-first. If two nodes does not have an internal sorting they must maintain the order they had from the incoming node-set (the first argument).

Notice that the use of this function makes it possible to change the way the sorting is done in runtime. This isn't possible with the sorting element. E.g. by storing different expressions in an instance it is possible to select a different expression for the sorting.

Example: how to use exf:sort
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node value="2">Node 1</node>
      <node value="1">Node 2</node>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:repeat nodeset="exf:sort(node, '@value', 'number')">
  <xforms:output ref="."/>
</xforms:repeat>

Will output Node 2 then Node 1

Example: how to use exf:sort to reverse document order
<xforms:model>
  <xforms:instance>
    <data xmlns="">
      <node value="2">Node 1</node>
      <node value="1">Node 2</node>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:repeat nodeset="exf:sort(node, 'position()', 'number', 'descending')">
  <xforms:output ref="."/>
</xforms:repeat>
Example: how to use exf:sort to change the sorting
<xforms:model>
  <xforms:instance>
    <data xmlns="" use-sort="1">
      <node value="2">Node 1</node>
      <node value="1">Node 2</node>
      <sort id="1">position()</sort>
      <sort id="2">@value</sort>
    </data>
  </xforms:instance>
</xforms:model>

<xforms:repeat nodeset="exf:sort(node, sort[/data/@use-sort=@id], 'number')">
  <xforms:output ref="."/>
</xforms:repeat>

<xforms:select1 ref="@use-sort">
  <xforms:label>Sort method:</xforms:label>
  <xforms:itemset nodeset="sort">
    <xforms:label ref="."/>
    <xforms:value ref="@id">
  </xforms:itemset>
</xforms:select1>

7 References

7.1 Normative References

XForms 1.0
XForms - Version 1.0, John M. Boyer, David Landwehr, Roland Merrick, T. V. Raman, Micah Dubinko, Leigh L. Klotz, Jr., 2006. W3C Recommendation available at: http://www.w3.org/TR/xforms/.
XML Events
XML Events - An events syntax for XML, Steven Pemberton, T. V. Raman, Shane P. McCarron, 2002. W3C Recommendation available at: http://www.w3.org/TR/xml-events/.
XPath 1.0
XML Path Language (XPath) Version 1.0, James Clark, Steve DeRose, 1999. W3C Recommendation available at: http://www.w3.org/TR/xpath.
XML Schema part 1
XML Schema Part 1: Structures, Henry S. Thompson, David Beech, Murray Maloney, Noah Mendelsohn, 2001. W3C Recommendation available at: http://www.w3.org/TR/xmlschema-1/.
XML Schema part 2
XML Schema Part 2: Datatypes, Paul V. Biron, Ashok Malhotra, 2001. W3C Recommendation available at: http://www.w3.org/TR/xmlschema-2/.
RFC 2119
RFC 2119: Key words for use in RFCs to Indicate Requirement Levels, S. Bradner, 1997. Available at http://www.ietf.org/rfc/rfc2119.txt.

A Acknowledgments (Non-Normative)

eXforms.org would like to thank the following for their contributions in creating the extensions:

  • David Landwehr, exforms.org / SolidApp
  • Kenneth Sklander, picoforms.com
  • Allan Beaufour, beaufour.dk