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.