Re: XPath and find/findAll methods

On Nov 23, 2011, at 01:08 , Jonas Sicking wrote:
> I really don't think that selectors can ever compete with the
> expressiveness of XPath. Consider the following expression:
> 
> //div[count(.//span) > 6][count(.//span[@data-foo = ../@data-bar]) mod 2 = 1]
> 
> This expression finds all <div> elements which has at least 6 <span>
> descendants and where an odd number of those <span> elements have a
> "data-foo" attribute equal to its parents "data-bar" attribute. It is
> obviously trivial to add arbitrary additional complexity to this
> expression.
> 
> Trying to do the same thing in Selectors will just result in a
> incomprehensible mess.

That's exactly what worries me with this plan.

> At the same time, XPath can't ever compete in expressiveness to
> Javascript. Finding all <div> elements with a "data-foo" attribute
> that contains a prime number is not possible in XPath but trivial in
> javascript.

Well, for values of trivial that could be quite slow :) But yes.

> I'm not convinced that it's worth investing in XPath. At least not
> beyond the low-hanging fruit of making most of the arguments to
> .evaluate optional. But I think trying to make selectors compete in
> expressiveness with XPath is a loosing battle.

I don't think that anyone has requested much beyond making the existing API actually usable (either by fixing it directly or by adding a new, simple one). That's all that's needed IMHO and it doesn't strike me as much.

I would be thinking about something along the lines of (untested, off the top of my head):

Node.prototype.queryXPath = function (xpath, ns) {
    ns = ns || {};
    var snap = this.ownerDocument
                   .evaluate(xpath,
                             this,
                             function (p) { return ns[p] || null; },
                             XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                             null);
    var ret = [];
    for (var i = 0; i < snap.snapshotLength; i++) ret.push(snap.snapshotItem(i));
    return ret;
};

or, if people prefer, even just:

Node.prototype.queryXPath = function (xpath) {
    var snap = this.ownerDocument
                   .evaluate(xpath,
                             this,
                             function () { return "http://www.w3.org/1999/xhtml"; },
                             XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                             null);
    var ret = [];
    for (var i = 0; i < snap.snapshotLength; i++) ret.push(snap.snapshotItem(i));
    return ret;
};

Which hardly strikes me as a terribly complex addition.

-- 
Robin Berjon - http://berjon.com/ - @robinberjon

Received on Wednesday, 23 November 2011 10:24:27 UTC