6 Dynamic Constraint Language


Contents

This chapter is normative.

6.1 Introduction

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.

Editor's Note: For simplicity, this chapter currently defines DCL as being based on XPath without subsetting. Readers should note, 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].

6.2 Datatypes

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.

Resource-limited XForms Processors may define implementation limits on the maximum size of a node-set.

[Editor's Feedback Request 6.2.conversions: 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. Comments from the community are welcome.]

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.

Editor's Note: The productions here currently do not properly reference and extend those found in XPath.

[1] Digit    ::=    [0-9]  
[2] HexDigit    ::=    Digit
| ['a' - 'f']
| ['A' - 'F']
 
[3] NullExp    ::=    'null'  
[4] BoolExp    ::=    'true' | 'false'  
[5] NumberExp    ::=    0x[HexDigit]+
| [['-']Digit+['.' Digit*] [('e' | 'E')['+' | '-']Digit+]
 
[6] StringExp    ::=    '"' NCName? '"' | "'" NCName? "'"  
[7] ArrayExp    ::=    '[]' | [Expr [',' Expr]*]  

6.3 Binding Expressions

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:

As in XPath, array indexes start at 1, not 0. 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:

To address the partNum attribute in the second item you could write:

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:

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.

[Editor's Feedback Request 6.3.ns: To what extent do binding expressions need to concern themselves with namespaces? (Note that for authoring simplicity, this proposal so far largely treats binding expressions in a non-namespace-aware fashion)]

[8] Identifier    ::=    (('/'
| '../'
| element-name) ['[' Expr ']'])+
 
[9] PathExp    ::=    identifier ['@' attribute-name]
| '@' attribute-name
 

6.3.1 Root and Context Nodes

Binding expressions are often used to point to a specific instance data item. When used in this role, the following rules determine how data is selected:

  1. The root node for binding expressions refers to the virtual instance data <instance> element. For example:
  2. For purposes of addressing, all instance data is treated as if it were a local resource.
  3. If a binding expression selects a node-set in a context where only a single node is required, by default only the first node from the node-set is used.
  4. The context node for outermost binding elements (such as XForms UI elements) is the virtual instance data root, defined above. A "binding element" is any element that is explicitly allowed to have an xform:ref attribute. An XForms element is "outermost" when the XPath expression ancestor::* includes no binding element nodes.
  5. The context node for non-outermost binding elements (such as XForms UI elements) is determined by evaluating the binding expression of the immediately enclosing element. An element is "immediately enclosing" when it is the first binding element node in the XPath expression ancestor::*. This is also called "scoped resolution".

Example:

Scoped Binding Expressions
<someGroupingWidget ref="element1/foo/bar">
  <anotherWidget ref="element2"/>
  <anotherWidget ref="@attr"/>
</someGroupingWidget>

In this example, the someGroupingWidget has a binding expression of element1/foo/bar. According to the rules above, this outermost element would have a context node of /, which is the <instance> element. Both of the anotherWidgets then inherit a context node from their parent, the context node being /element1/foo/bar. Based on this, the anotherWidget binding expressions evaluate respectively to /element1/foo/bar/element2 and /element1/foo/bar/@attr. Matching instance data follows:

Sample Instance Data
<instance xmlns="http://www.w3.org/2001/02/xforms">
  <element1 xmlns="...">
    <foo>
      <bar attr="xyz">
        <element2>xyz</element2>
      </bar>
    </foo>
  </element1>
</instance>

Here is a sample instance data that fits the above UI markup. "xyz" indicates sample data.

In some cases, binding expressions address the XForms Model, for instance to select dynamic constraints or calculations. This operates similar to the above.

Editor's Note: A future revision will explain this in greater detail, including an example.

6.3.2 Canonical Binding Expressions

As with XPath, it is possible to construct many different binding expressions that end up pointing to the same location. That said, it is often useful to express a binding expression in a standard, compact representation, called a canonical binding expression.

Canonical binding expressions are represented as a AbsoluteLocationPath as defined in [XPath]. Additionally, canonical binding expressions use only default axis-specifiers (for elements) or the '@' abbreviation (for attributes). Examples:

6.4 Operators

Editor's Note: Some 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:

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:

The and, or and xor require Boolean operands and perform the corresponding Boolean operations. For instance, the following examples are all 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:

The % operator is a postfix operator that divides its operand by 100.

The = operator performs assignment. The mechanism for binding form controls generally assumes that each form control is bound to a single model item. Some XForms 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:

[10] InfixOperator    ::=    'and'
| 'or'
| 'xor'
| 'plus'
| 'minus'
| 'times'
| 'over'
| 'is' [[PrefixOperator] ('above' | 'below' | 'before' | 'after')]
 
[11] InfixExp    ::=    Expr InfixOperator Expr  
[12] PrefixOperator    ::=    'not'  
[13] PrefixExp    ::=    PrefixOperator Expr  
[14] PostfixOperator    ::=    '%'  
[15] PostfixExp    ::=    Expr PostfixOperator  
[16] SpecialOperator    ::=    'is' ['not'] 'within'  
[17] SpecialExp    ::=    Expr SpecialOperator '(' Expr ',' Expr ')'  
[18] IfThenElseExp    ::=    'if' Expr 'then' Expr ['else' Expr]  
[19] Assignment    ::=    [Lexpr '=' ]+ Expr [ ';' Assignment ]* [ ';' ]  
[20] Lexpr    ::=    Identifier |
Function |
(Lexpr)
 

6.5 XForms Core Function Library

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]*] ')'  

6.5.1 XPath Core Function Library

The XForms Core Function Library includes the entire [XPath] Core Function Library, including operations on node-sets, strings, numbers, and booleans.

Editor's Note: Further input is required on the ability for resource-constrained devices to implement the complete XPath Core Function Library.

6.5.2 Number Methods

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.

6.5.3 String Methods

Note: the following are defined within [XPath] - string(), concat(), starts-with(), contains(), substring-before(), substring-after(), substring(), string-length(), normalize-space(), and translate().

6.5.4 Date/Time Methods

Function: string now()

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.

6.5.5 Miscellaneous Methods

Function: null submit()

The submit function immediately submits the instance data bound to the node that contains the expression.

Function: null reset()

The reset function immediately resets the instance data bound to the node that contains the expression.

6.6 Lexical Structure

When tokenizing, the longest possible token is always returned.

Whitespace is permitted between tokens with the following exceptions:

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
 

6.7 Extensibility

This section will be expanded in future revisions, to cover extension functions and methods for calling out to script.