On 10/29/2010 7:17 PM, P T Withington wrote:
On 2010-10-28, at 19:48, André Bargull wrote:

And here's the updated version of<replicator>#setData() which fixes this issue. (The 
internal<datapointer>#parsePath() is required to get the LzParsedPath instance.)


  <method name="setData" args="v:*,n=null"><![CDATA[
    if (v) {
      v.setAttribute('data', this.nodes[ n ]);
      var ptr = this._pointer;
      if (ptr) {
        var ppath = ptr.parsePath(this.xpath);
        if (ppath &&  (ppath.operator != null || ppath.aggOperator != null)) {
          v.applyData(this.nodes[n]);
        }
      } else {
        // other data-source
        v.applyData(this.nodes[n]);
      }
    }
  ]]></method>


Surely the "lazy developer" is me.  Really just that the developer cannot wrap 
his head around datapath/pointers.  And I still don't get it.  Can you explain your 
change a little more?  Is simply calling `parsePath` somehow side-effecting `nodes`?


Aha, lazy Tucker on work! No really, lazy was meant as in "Hey unknown developer, you did not spend weeks with trying to grasp the datapointer/-path classes. Oh man, you're really lazy!" :-p

Back to your question:
I'm using parsePath() to parse the xpath to an instance of LzParsedPath, which is our internal representation of xpaths. parsePath() has no side-effects on the datapointer it's called on (well, except for the shared, _unlimited_ cache in datapointer, but that's another story). With that LzParsedPath instance it's possible to find out what the xpath is actually doing, for example whether it ends with "text()" or "last()" etc. And if the xpath ends with @xxx, @*, name(), serialize(), text(), last() or position() (aka a terminal selector) the "operator" resp. "aggOperator" property is non-null. That means you could also use a reg-exp like: /(?:@\*|[^/\]+])|(?:(?:name|text|serialize|position|last)\(\))$/ and run that against the xpath.

[^/\]+ is used to match attribute names, super simplified, but the actual regular expression for xml names is just so long...

But I doubt that expression easier to understand?!

So the "operator != null || aggOperator != null" is needed to filter out xpaths with terminal selectors. Terminal selector also means that the xpath evaluates to a simple type (string,number,boolean). And only simple types should be should be presented to the datapath's parent through applyData().

The current bug Henry is seeing, is based on fact that applyData() is called with a data-element, which is not a simple type by the definition from above. That said, we need to ensure that applyData() is only called xpaths with terminal selectors. Other way around, we need to ensure applyData() is only called for simple types:
if (v) {
  var data = this.nodes[n];
  v.setAttribute('data', data);
  if (data is Boolean || data is Number || data is String) {
    v.applyData(data);
  } else if (data == null) {
    // I'm not sure what to do in this case, requires some tests to check what 
datapath is doing here...
  }
}

That code is simpler and easier to understand, but I'm not sure about the "data == null" case, or what to do for "@*", which returns an Object. For these reasons I've used the same check as in <datapath>#__LZApplyData() (=> "operator!=null || aggOperator!=null") to get things right.

Reply via email to