Unified evaluation context

From W3C XForms Group Wiki (Public)

Proposed text

MIP elements

Calculate Element

When it appears as a child element of bind, the calculate element provides the calculate expression, overriding the calculate attribute. And by consequence there is no difference in processing a calculate expression defined by the calculate attribute and the calculate element.

Common Attributes: None

Special Attributes:

value

   Attribute containing an XPath calculate expression to evaluate using the in-scope evaluation context.

context

   Optional attribute containing an XPath expression evaluated using the in-scope evaluation context. The result of the XPath expression is used to override the in-scope evaluation context. If the result is not a not empty nodeset the first node of the nodeset is used as the new in-scope evaluation context node, and the context position and size are set to 1. By adjusting the in-scope evaluation context, this attribute affects the evaluation of subsequent attributes that may appear on the calculate element, including value.

Examples

<bind nodeset="result">
   <calculate context="instance('X')" value="a+b"/>
</bind>


<bind nodeset="purchaseorder/items/item/lineTotal">
  <calculate context=".." value="quantity * price"/>
</bind>


Pending questions

  • NickVdB: If the context attribute is used on insert and delete, only the first node of the nodeset returned by the XPath expression is used as the new in-scope evaluation context. But I think we don't want to limit the new in-scope evaluation context by specifying context on the bind childs to be limited to the first node.
    • We can use the same definition as insert bind will create a calculate for each node in its nodeset

Emails

More recent post from JohnBoyer:


Hi Nick,

I thought we had discussed a syntax that was better than the original 
proposal, namely that each possible MIP could possibly be expressed by a 
child element of the same name, whereupon the context attribute could be 
used on that element.  Like this:

<bind nodeset="c">
    <calculate context=".." value="a + b"/>
</bind>

This has several benefits.

First, it is easier to say that the *bind* identifies the nodes to which 
MIPs are applied, whereas the <calculate> element is only concerned with 
providing a more sophisticated way of expressing the formula.  There is no 
confusion about what node the formula applies to because the context 
attribute is not being placed on an inner bind.  In other words, it is 
easier to say that context on the calculate element only overrides the 
evaluation context of the value attribute and does not interfere in any 
way with the node to which the result of the formula is applied.

Second, it allows us to simplify the expression of boolean results.  For 
example, must we really call boolean-from-string() on expressions whose 
result is known to be boolean?  Specifically, the element relevant could 
be defined as automatically applying boolean-from-string to the string 
result of the value attribute in the following:

<bind nodeset="node/a">
    <relevant context=".." value="b"/>
</bind>

It's up to the group to decide if they want this extra semantic for 
relevant, readonly and constraint, but lots of people consistently forget 
to put boolean-from-string() until they get burnt by it.  Even if we used 
'boolean' rather than 'value', it would be better, e.g.

<bind nodeset="node/a">
    <relevant context=".." boolean="b"/>
    <readonly context=".." boolean="c"/>
</bind>

Third, using MIP named child elements allows the possibility for 
combinators on some of the MIP types, especially constraint, e.g. the 
following would say that node a is invalid unless (b and c and (d or e) 
and (not f)):

<bind nodeset="node/a">
    <constraint context=".." operator="and">
          <constraint boolean="b"/>
          <constraint boolean="c"/>
          <constraint operator="or">
                 <constraint boolean="d"/>
                 <constraint boolean="e"/>
         </constraint>
          <constraint operator="not" boolean="f"/>
    </constraint>
</bind>


Original post from JohnBoyer:


Date: Thu, 19 Apr 2007 03:03:43 +0200
To: www-forms-editor@w3.org
Subject: LC: Problems with Binding Expressions changing evaluation context of other  attributes
From: "John Boyer" <boyerj@ca.ibm.com>

Once a binding expression on an element is evaluated, XForms uses the
identified node as the context node for other attributes on the same
element.

One example where that creates a limitation is given in the following last
call comment:
http://lists.w3.org/Archives/Public/www-forms-editor/2007Apr/0042.html

But other cases exist.  For example, if an instance has three instance
nodes as follows:

<data>
   <a>2</a>
   <b>2</b>
   <c>4</c>
</data>

then one must write the following to put the result of a+b into c:

<bind nodeset="c" calculate="../a + ../b"/>

The excessive dots are a nuisance, and when the novice writes what is
reasonable to expect-- calculate="a+b"-- the result is NaN.  This is
because the calculate is interpreted relative to the node c, and the node
c has no child elements named a and b.  The dots are needed to traverse up
to the parent of c so that its siblings may be obtained.

The problem becomes more acute in larger formulae, which occur often in
constraints.

It should be noted that fixing this problem might mean that the above bind
would no longer be equal to the following nested bind (because the outer
bind sets the evaluation context for the inner bind):

<bind nodeset="c">
     <bind calculate="../a + ../b"/>
</bind>

It is a decision point as to whether preserving that equivalence between
the nested and non-nested bind is important.  If not, then the nested bind
would give another way to get the old 1.0 behavior back for those who want
it.  If so, then that might simply affect how the problem is solved.

Needless to say, it would be too problematic for the existing XForms
community to do away with the current method of determining the evaluation
context for attributes like @calculate on bind or @value on setvalue.  So
we would need some kind of attribute for turning on a different method.
This attribute could *default* to the new method when the XForms model
@version attribute is set to 1.1.

Perhaps something like <model unifiedcontext="false" version="1.1" ...>
would suffice to keep the old context evaluation in 1.0, and one could
optionally write unifiedcontext="true" to make the change to having all
attributes of an element use the same eval context.  And,
unifiedcontext="true" could be the default for version="1.1" XForms.

I don't have a good solution yet for how this could be done if the nested
bind and non-nested bind cases above must remain equivalent, but last call
rules say my proposal does not have to be complete, and in this case, I
call out this equivalence as a decision point, so we don't have to solve
it if the answer is no.

John M. Boyer, Ph.D.


Proposal from call:

<bind nodeset="result"> <calculate context="instance('X')" value="a+b"/></bind>

John Boyer