Rationale
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!).
Compatibility notes
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 if() function:
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
string
- the XPath 2 function takes an
xs:dateTime
- 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 $arg"
[SINCE: 2011-02-24]
- 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.
Type annotations
Basics
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:
<xforms:bind
ref="age"
type="xs:positiveInteger"
constraint="xs:integer(.) le 150"/>
With exposing type annotations, you can simply write:
<xforms:bind
ref="age"
type="xs:positiveInteger"
constraint=". le 150"/>
or:
<xforms:bind
ref="date"
type="xs:date"
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:
<xf:model xxf:expose-xpath-types="true">
[SINCE 2013-04-24 / Orbeon Forms 4.2]
You can also enable this on a per-instance basis:
<xf:instance xxf:expose-xpath-types="true">
Where does this work?
With Orbeon Forms 4.0
Static type annotations (with xforms:bind/@type and xsi:type) can be used by all XPath expressions, including xforms:bind/@calculate.
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
xforms:bind/@type and 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:
xforms:bind/@constraint
- actions
- 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
Consider: <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()">
Or:
<xforms:action if="data(is-soap)">
Or:
<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.
Consider:
<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!
|