Fixing insert/delete context

Hi everyone,

I'm pretty sure Erik briefly raised this when we spoke about iterate, but 
the conversation moved on without our fully digging into this...

Since we're adding the context attribute everywhere and also adding the 
iterate attribute to optimize data iteration action sequences, we really 
ought to repair the context attribute as applied to the insert and delete 
actions in XForms 1.1.

The problem is that the context attribute should only perform the first 
function below, but it is performing both:
1) override the default in-scope evaluation context
2) provide the parent of the nodeset in which to insert if the nodeset is 
empty

The latter function should be controlled by a second attribute, perhaps 
named "parent".

Without this change, it is either impossible or hard to understand the 
impact of the context attribute on function #2 above when used in 
combination with the iterate attribute.

Note that the context attribute is evaluated first for all elements and 
overrides the in-scope evaluation context used in other attributes, 
including iterate, while and if.

As an example, I'd like to be able to reverse the nodes of a list with an 
action sequence along the lines of this:

<xforms:action ev:event="custom-reverse">
     <xforms:insert context="some/list" iterate="*" origin="."/>
     <xforms:delete nodeset="some/list/*[position()*2 > last()]"/>
</xforms:action>

The first line obtains the parent node of some list, then iterates its 
children and prepends each to the front of some/list.  While this *could* 
work, I think it shouldn't.  The iterate attribute will repeat an action, 
except for its context and iterate attributes, so I think the iterated 
insert action has neither an expressed context nor an expressed nodeset 
attribute.  I think I should have to use this:

<xforms:action ev:event="custom-reverse">
     <xforms:insert context="some/list" iterate="*" parent=".." 
origin="."/>
     <xforms:delete nodeset="some/list/*[position()*2 > last()]"/>
</xforms:action>

One can attempt to reverse the order of evaluationg iterate and context 
using an action element nesting, like this:

<xforms:action ev:event="custom-reverse">
   <xforms:action iterate="some/list/*">
     <xforms:insert context=".." origin="???"/>
   </xforms:action>
   <xforms:delete nodeset="some/list/*[position()*2 > last()]"/>
</xforms:action>

But, one can no longer use origin="." because the context attribute resets 
the meaning.  Nor can one use origin="context()" because the context 
attribute resets that, too.  One is therefore forced to use a nodeset 
attribute instead, like this:

<xforms:action ev:event="custom-reverse">
   <xforms:action iterate="some/list/*">
     <xforms:insert nodeset="../*" at="1" position="before" origin="."/>
   </xforms:action>
   <xforms:delete nodeset="some/list/*[position()*2 > last()]"/>
</xforms:action>

One ugly aspect of this insert is that its nodeset attribute will match 
all of the original N nodes (plus all the inserted ones) for each of the N 
inserted nodes, so you get O(N^2) performance.  Now, you can add [1] to 
the nodeset attribute and then cross a small army of fingers and toes with 
the hope that it will cause the xpath engine to use an optimized version 
of [1].

But in reality, I simply shouldn't have to know this much to get it right. 
 If I use context and iterate on the same insert, I should get a binding 
exception that informs me that one of "parent" or a "nodeset binding" is 
required.  Or if I want to use nesting for clarity, I should be able to 
type this:

<xforms:action ev:event="custom-reverse">
   <xforms:action iterate="some/list/*">
     <xforms:insert parent=".." origin="."/>
   </xforms:action>
   <xforms:delete nodeset="some/list/*[position()*2 > last()]"/>
</xforms:action>

Finally, note that we added context to delete in XForms 1.1 so that insert 
and delete could be written in a consistent manner.  On the other hand, 
the parent behavior really is a special case of insert, and there really 
is no good analog in delete, so it could go either way -- add "parent" or 
don't add "parent" as a special attribute of delete.  But if we do add it 
to delete, then it should probably be added to repeat as well so that 
insert, delete and repeat nodeset expressions can be written in the same 
way. 

Thanks,
John M. Boyer, Ph.D.
Distinguished Engineer, IBM Forms and Smarter Web Applications
IBM Canada Software Lab, Victoria
E-Mail: boyerj@ca.ibm.com 

Blog: http://www.ibm.com/developerworks/blogs/page/JohnBoyer
Blog RSS feed: 
http://www.ibm.com/developerworks/blogs/rss/JohnBoyer?flavor=rssdw

Received on Monday, 31 October 2011 14:00:10 UTC