E4X filtering in Spidermonkey
I'm using E4X in SpiderMonkey, and the majority of the language seems pretty solid, but I can't get filtering to work:
var xml = <root>
<person id="dave">Dave</person>
<person id="ian">Ian</person>
<person>John</person>
</root>
trace( xml.*.(name() == 'person') );
trace( xml.*.(attribute('@id')) );
Expected:
<person id="dave">Dave</person>
<person id="ian">Ian</person>
<person>John</person>
<pers开发者_StackOverflow社区on id="dave">Dave</person>
<person id="ian">Ian</person>
Results:
ReferenceError: name is not defined
ReferenceError: attribute is not defined
I can't even get hasOwnProperty() to work either:
xml.*.(trace( hasOwnProperty('@id') ));
false
false
false
Specifically, I'm using JSFL in Flash, which uses the SpiderMonkey engine.
From my basic knowledge of E4X so far, this is pretty unexpected / buggy, right? As I can get these expressions to work just fine in ActionScript / FlashPlayer!
Thanks, Dave
OK, so I've tried a bunch of things, and I still can't get the original syntax to work, so the best I can come with (it's a pretty good workaround, considering) is to extend the XMLList prototype and add a filter() method:
XMLList.prototype.function::filter = function(callback)
{
var output = new XMLList();
var length = input.length();
for(var i = 0; i < length; i++)
{
if(callback(input[i], i, input))
{
output += input[i];
}
}
return output;
}
So with the following XML...
var xml = <root>
<person id="dave">Dave</person>
<person id="ian">Ian</person>
<person>John</person>
<group>
<person id="jane">Jane</person>
<person>Sarah</person>
</group>
</root>
It's pretty intuitive to grab and filter nodes:
// old
var nodes = xml..person.( hasOwnProperty('@id') );
// new
var nodes = xml..person.filter( function(node){ return node.hasOwnProperty('@id'); } );
<person id="dave">Dave</person>
<person id="ian">Ian</person>
<person id="jane">Jane</person>
If anyone can correct me on this, I'd be super-glad, if not, I'd just like to know why my original filtering just didn't work.
Dave
Just a small correction for the answer posted here, regarding the filter
function:
XMLList.prototype.function::filter = function(callback)
{
var output = new XMLList();
var input = this;
var length = input.length();
for(var i = 0; i < length; i++) {
//console.println(i + ", " + input[i]);
if(callback(input[i], i, input))
{
//console.println("Yes");
output += input[i];
}
}
//console.println('output = ' + output);
return output;
}
The original solution is the best and that was exactly what I was looking for!
精彩评论