This chapter is normative.
Many forms define integrity constraints that act over multiple fields. For example, the total value of an order can be defined in terms of a computation over other values such as unit prices, quantities, discounts, and tax and shipping costs. Such computations can be conveniently represented using the syntax outlined in here. This chapter describes an XForms Dynamic Constraints Language (DCL) based on XPath that enables these types of expressions without the use of a separate scripting language.
Dynamic Constraints are also useful for declaratively stating when a form control or subform needs to be filled out, according to some other value. A further use is to functionally define the acceptable choices for some form control, when this depends on other values.
Note: For simplicity, this chapter currently defines DCL as being based on XPath without subsetting. However, there is not yet consensus within the XForms Working Group on this matter. Specific points under consideration are noted throughout this chapter.
In the following grammar, the non-terminal NCName is defined in [XML Names], and S is defined in [XML 1.0].
XForms Dynamic Constraints are built out of the XForms data types:
The string, boolean, and number types correspond to those defined in XPath. Dates, time durations and monetary values etc. are subtypes of string. Additionally, the XPath datatypes node-set and null are allowed in the XForms Dynamic Constraint Language.
Note: Resource-limited XForms Processors may define implementation limits on the maximum size of a node-set.
Issue: XPath defines specific type conversions. The XForms Working Group is considering whether to include or exclude these as part of XForms Dynamic Constraints. Either way, there will be well-defined semantics of operations involving differing types.
If an operation cannot be performed an exception will be thrown. Exceptions are treated as events and can be caught using event handlers, declared in XML or in scripts.
Standalone XForms Datatypes are considered valid XForms Dynamic Constraints.
[Ed: The productions here currently do not properly reference and extend those found in XPath.]
Like XPath, the XForms DCL models an XML document as a tree of nodes. There
are different types of nodes, including element nodes, attribute nodes and text
nodes. XPath uses '/
' as a location-step separator. XML doesn't
permit the '/
' character within element or attribute names, so
this is unambiguous.
XPath additionally allows an array index notation to address the n-th element in a sequence, for example, the line items in a purchase order.
<purchaseOrder orderDate="1999-10-20"> <item partNum="872-AA"> ... </item> <item partNum="926-AA"> ... </item> </purchaseOrder>
The second item in the purchase order could be addressed as follows:
purchaseOrder/item[2]
Many programming languages, including ECMAScript and Java, use zero rather than one for the index number for the first item in an array. Authors should be aware of this, especially when writing applications that combine scripting and XForms.
XPath also allows you to address attributes. For instance, the orderDate
attribute in the purchaseOrder
element could be addressed as follows:
purchaseOrder/@orderDate
To address the partNum
attribute in the second item you could
write:
purchaseOrder/item[2]/@partNum
As with XPath, all addressing is based on the concept of a context node. In
many situations, using a context node can lead to shorter identifiers. As an
example, if the second item
element above was selected as the context
node, the partNum
attribute could be addressed as follows:
@partNum
Identifiers are evaluated from left to right. The value of an identifier must resolve to one of the above types. The identifier syntax is a based on XPath and follows the same semantics. If an identifier starts with an element name, then the name must be in the current context (scope) or an ancestor context. If an identifier can't be resolved, an invalid identifier exception is thrown.
[8] | Identifier | ::= | (('/' | '../' | element-name) ['[' Expr ']'])+ |
|
[9] | PathExp | ::= | identifier ['@' attribute-name] | '@' attribute-name |
XForms applications may need access to data beyond that immediately present in an XForms Model. Some possible examples include: the user's locale, information about the XForms Processor's capabilities, the user's name and address, location information for a mobile device, and temporary data which won't be submitted to the server. The XForms application may be part of a suite of applications that share a common data context. An architecture is needed that describes the relationship between data spaces as well as the access control mechanisms needed for security and privacy.
A given constraint may need to refer to multiple data spaces. There are several ways in principle that this could be achieved:
Library functions. A function call can provide the appropriate context for resolving an address within the desired data space.
Multiple root nodes. If each data space is associated with its own XML 'document', then the data spaces could be distinguished by the use of different root nodes.
Inheritance in nested data spaces. If the data spaces are nested one within another, an inheritance mechanism could be used to inherit names from a parent data space. For instance the XML form could be included within the application data space, and in turn within a browser data space.
Note that XML namespaces solve a different problem. XPath permits the use of an XML namespace prefix for element names, but the element is still assumed to be in the same node tree. XML namespaces provide a way for XML documents to distinguish elements which have the same name but different semantics.
A small amount of work is still needed to specify operator precedence, associativity and the event names thrown upon exceptions.
XPath reserves '/
' as a location-step separator, making it impractical
to also use this symbol for division. The Dynamic Constraints Language makes
consistent use of English names for operators is intended to minimize the potential
for authoring errors, and to avoid the need for using character entity references
for symbols.
The not
operator can only be used with an operand that
evaluates to a boolean value. If the operand is true
, the not
operator evaluates to false
. If the operand is false
,
the not
operator evaluates to true
.
The if
cond then
expr1
else
expr2 construct requires cond to evaluate
to true
or false
. If cond is true
,
the value of the construct is the result of evaluating expr1, otherwise
it is obtained from evaluating expr2.
The is
operator compares two values, and produces a Boolean
result.
The expr is within
(expr1, expr2) construct
evaluates to true
if the result from evaluating expr falls
within the inclusive range defined by expr1 and expr2. If it falls
outside the range the construct evaluates to false
. The operands
must be of the same type, and are restricted to numbers, strings, dates, times
or monetary values with the same currency code. String comparison is defined
as per the Unicode standard.
The expr is not within
(expr1, expr2)
construct evaluates to false
if the result from evaluating expr
falls within the inclusive range defined by expr1 and expr2. If
it falls outside the range the construct evaluates to true
. The
operands must be of the same type, and are restricted to numbers, strings, dates,
times or monetary values with the same currency code. String comparison is defined
as per the Unicode standard. Here are some examples of true
statements:
3 is within(1,5)
3 is not within(1,2)
"aab" is within("aaa", "aac")
The is before
and related operators provide comparison
operations similar to is within
. The operands must be of
the same type, and are restricted to numbers, strings, dates, times or monetary
values with the same currency code. String comparison is defined as per the
Unicode standard. Before and below denote earlier in the scalar range, while
after and above denote later in the scalar range. For instance, here are some
examples of true
statements:
age is 60
26 is not 27
3 is below 4
"Mary" is after "Mandy"
The and
, or
and xor
require
Boolean operands and perform the corresponding Boolean operations. For instance,
the following examples are all true
:
false is true and false
true is true or false
true is true xor false
false is true xor true
The plus
, minus
, times
and over
operators require numeric operands (see below for exceptions) and perform the
corresponding arithmetic operations. The over
operator performs
division and throws an overflow exception if the denominator is zero. The plus
operator can also be applied to string operands, to perform string concatenation.
The following examples are all true
:
5 is 1 plus 4
3 is 6 over 2
3 is 5 minus 2
"happy days" is "happy" plus " " plus "days"
The %
operator is a postfix operator that divides its operand
by 100.
9 is 15% times 60
The =
operator performs assignment. The mechanism for binding
XForms User Interface controls
generally assumes that each form control
is bound to a single model item. Some
user interface controls such as buttons and image-maps may need to set the values
of several model items in the same action.
It is proposed that this is handled using one or more assignment statements
separated by semicolons:
Here is a simple example which sets both the city and state:
city="London"; state="Ontario"
This section defines a set of required functions useful within XForms. Function syntax is based on XPath:
[21] | Arg | ::= | Expr | |
[22] | FunctionExp | ::= | function-name '('[arg [',' arg]*] ')' |
The XForms Core Function Library includes the entire [XPath] Core Function Library, including operations on node-sets, strings, numbers, and booleans.
Further input is required on the ability for resource-constrained devices to implement the complete XPath Core Function Library.
Note: the following are defined within [XPath]
- number(), sum(), floor(), ceiling(), and round()
Function: number average(node-set)
The average function returns the arithmetic average value, for each node in the argument node-set, of the result of converting the string-values of the node to a number. Numbers are added with plus, and then taken over the count() of the specified node-set.
Function: number min(node-set)
The min function returns the minimum value, for each node in the argument node-set, of the result of converting the string-values of the node to a number. Numbers are compared with is below.
Function: number max(node-set)
The max function returns the arithmetic average value, for each node in the argument node-set, of the result of converting the string-values of the node to a number. Numbers are compared with is below.
Note: the following are defined within [XPath]
- string(), concat(), starts-with(), contains(), substring-before(), substring-after(),
substring(), string-length(), normalize-space(), and translate().
The now function returns the current system time as a string value, in the canonical format defined within the XForms specification. If local time zone information is available, it is included in the string.
The submit function immediately submits the instance data bound to the node that contains the expression.
The reset function immediately resets the instance data bound to the node that contains the expression.
When tokenizing, the longest possible token is always returned.
White space is permitted between tokens with the following exceptions:
/
or ../
within compound identifiers.Whitespace is required between adjacent alphanumeric tokens, e.g. white space
is required between the operator "not
" and the name of a function.
Names follow the lexical rules for XML NAME tokens. Function names, however,
are not permitted to include -
or .
for compatibility
with externally defined functions.
Parentheses can be used for grouping, but otherwise have no effect on the semantics of Dynamic Constraints. The syntax caters for literals for null, booleans, numbers, and strings.
[23] | Expr | ::= | NullExp | BoolExp | NumberExp | StringExp | ArrayExp | PathExp | InfixExp | PrefixExp | PostfixExp | SpecialExp | IfThenElseExp |
This section will be expanded in future revisions, to cover extension functions and methods for calling out to script.