Mechanical

Dear Lazyweb Techie Types

Got an annoying little problem. I wrote the following Greasemonkey script. What this does, when I go out to the Web site use.perl.org is ignore one particularly obnoxious user by simply erasing his comments.

// ==UserScript==
// @name           ignore.use.perl
// @namespace      http://publius-ovidius.livejournal.com/
// @description    Hide Annoying Users
// @include        http://use.perl.org/*
// ==/UserScript==

(function() {
    var user = 'some_user_name';
    var href = '//use.perl.org/~'+user+'/';

    var divs = document.evaluate(
        "//div[@class='full']/div/div[@class='details']/a[@href='"+href+"']",
        document,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );

    for ( var i=0; i < divs.snapshotLength; i++ ) {
        var node       = divs.snapshotItem(i).parentNode.parentNode.parentNode;
        node.innerHTML = '<p><strong>Ignoring '+user+' via GreaseMonkey</strong></p>';
    }
})();

In other words, until they restructure use.perl, I will never have to see that user's comments again. However, the code is annoying the heck out of me. I had to write:

        var node       = divs.snapshotItem(i).parentNode.parentNode.parentNode;

That's because of how the XPath is written:

        "//div[@class='full']/div/div[@class='details']/a[@href='"+href+"']",

Because I have to descend several levels deep into the node structure, I have to keep calling parentNode to walk back up the tree. With Perl regular expressions, we have 'positive look ahead assertions'. These allow me to match text which is followed by some other text, but ignore that other text for purposes of capturing data. If I had that with XPath, I could say "match any top level node followed by other nodes, but ignore those other nodes. Then I wouldn't have that awful series of parentNode calls. Is this possible in XPath?

You should just be able to use a more complicated predicate (the "where clause" in [the brackets]) to get what you're after. I couldn't find an article/page on useperl that fit your path expression, so here's an example of what I mean using my own friends page.

//table[@class='entrybox' and .//font/text()='jwz' ]

This finds any table on the page which

1. Has a class of entrybox

2. Has a child with a text value of jwz.

One of the powerful things about xpath is that the predicates are also xpath expressions

Also, if you're writing a lot of xpath that works on browser pages, this extension is pretty handy.

(saw this on the Portland Gothic friends list)

To help your understanding along: it is entirely valid to write something /div/@class. There is nothing about [] that makes it specific to attributes. In other words:

"//div[@class='full' and div/div[@class='details']/a[@href='"+href+"']]"

And then drop the .parentNodes.

I was tempted to answer that, but I'm trying to change how I interact on the Web and stay out of drama. Probably won't last long, though :)