XForms 1.1 only specifies support for XPath 1.0 in XForms. On the other hand Orbeon Forms supports XPath 2.0 out of the box.
This allows much greater flexibility in the expressions you can use in Orbeon Forms (and once you have tasted XPath 2.0, you won't want to go back to XPath 1.0!).
In general, using XPath 2.0 does not cause incompatibilities: most XPath 1.0 expressions work without issues with an XPath 2.0 implementation.
XForms if() function
The use of the XForms 1.0/1.1 if() function clashes with XPath 2.0's built-in if (...) then ... else ... construct.
The bottom line is that you cannot directly use the XForms if() function in Orbeon Forms. The following, for example, will not work in Orbeon Forms:
if (normalize-space(/first-name) = '', '', concat('Hello, ', /first-name, '!'))
The good news is that you have ways around this issue:
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
xforms:if() extension, which behaves like the XForms
xforms:if (normalize-space(/first-name) = '', '', concat('Hello, ', /first-name, '!'))
XForms seconds-from-dateTime() function
The XForms 1.0/1.1
seconds-from-dateTime() function clashes with the XPath 2.0 function of the same name:
- they take a parameter of different types
- the XForms 1.1 function takes a
- the XPath 2 function takes an
- they do not have the same semantic
- the XForms 1.1 function returns "the number of seconds difference between the specified dateTime (normalized to UTC) and 1970-01-01T00:00:00Z"
- the XPath 2 function returns "an
xs:decimal value greater than or equal to zero and less than 60, representing the seconds and fractional seconds in the localized value of
- The XForms version of the function is available as xforms:seconds-from-dateTime().
- The XPath 2.0 version of the function is available without a namespace as seconds-from-dateTime().
Using XPath 2.0
You can use XPath 2.0 expressions everywhere XForms allows XPath expressions.
Since July 2009, Orbeon Forms supports exposing MIP type annotations to XPath 2.0.
This means that if you have a type associated with a node, e.g.:
<xforms:bind ref="age" type="xs:positiveInteger"/>
then the type is not only used for validation, but also determines the typed value of the element node age
This means that earlier, you had to write the following:
constraint="xs:integer(.) le 150"/>
With exposing type annotations, you can simply write:
constraint=". le 150"/>
constraint=". le (current-date() + xdt:dayTimeDuration('P2D'))"/>
Enabling type annotations
NOTE: As of February 15, 2013 / Orbeon Forms 4.0, type annotations are not automatically enabled for backward compatibility reasons. However, they are enabled by default for new forms created with Form Builder.
The following property controls whether instance types annotations are exposed to XPath 2.0 expressions:
<property as="xs:boolean" name="oxf.xforms.expose-xpath-types" value="true"/>
- If set to false (the default), instance types are not made available to XPath expressions.
- If set to true, they are made available.
You can as usual enable this on a per-page basis:
[SINCE 2013-04-24 / Orbeon Forms 4.2]
You can also enable this on a per-instance basis:
Where does this work?
With Orbeon Forms 4.0
Static type annotations (with
xsi:type) can be used by all XPath expressions, including
NOTE: Here is the order in which the XForms engine processes type annotations in the model:
- during a model rebuild, all
xforms:bind point to there associated instance nodes if any
- static type annotations with
xsi:type are available just after a rebuild
- this means that type annotations can be used during subsequent model recalculate and revalidate
- however, annotations done via a schema are not reliably available during recalculate
With Orbeon Forms 3.9
Type annotations can be used in:
- control bindings and attributes
Type annotations currently don't work in:
The reason for that is that calculations occur during the recalculation
phase of the model, and type annotations are computed during the revalidation
phase of the model, which usually takes place later. So the types are not available during revalidation.
Caveat: Boolean comparisons
<xforms:bind ref="is-soap" type="xs:boolean"/>
<xforms:action if="is-soap = 'true'">
This will cause an XPath dynamic error, because 'true' is a string and XPath will atomize (get an atomic value) the content of the
is-soap node, which results in a boolean. Because there is no automatic conversion between the two, and error is raised and the action won't run. Instead, write:
<xforms:action if="is-soap = true()">
<xforms:action if="string(is-soap) = 'true'">
This latter expression works whether type annotations are enabled or not.
Caveat: XForms requested type vs. XPath typed value
With Orbeon Forms 4.0
When type annotations are enabled and an XPath expression requires access to a typed value, if the value is not of the specified type, the expression stops its evaluation. This behavior is different from 3.9, where an untyped value would be returned instead.
With Orbeon Forms 3.9
As per XPath 2.0 semantic, when XPath expressions access typed nodes, they expect them to have valid values for the given type.
In order to match this semantic:
- The XForms engine passes an XForms type to the XPath engine for a
node only if that node contains a value actually matching that type.
- Otherwise, the XForms engine tells the XPath engine that the value is untyped.
<xforms:bind nodeset="name" type="xs:NCName"
<xforms:output value="concat(name, '-suffix')"
In this example, if the node called name has e.g. an empty value, it will be marked as invalid. But in addition, the XPath expression in xforms:output would cause an XPath dynamic error if the type of the node as seen by XPath was xs:NCName, because the value is not of type NCName when empty. In this case, therefore, the XForms engine does not pass to XPath the xs:NCName
type, but mark it instead as untyped. In other words, depending on the
data on which it runs, an XPath expression might see the typed you
specified for the node, or it might see an untyped value.
The above means you must be just a bit more cautious about which types you use with type annotations!