Using Chrome’s XPath with jQuery

Detail photo of chrome on a car. Detail photo of chrome on a car.

While working with the Chrome Developer Tool, I've discovered that you can retrieve the XPath of a selected node. It'll return something like: //*[@id="top"]/div[1]/div[1].

XPath can be copied from Chrome's Developer Tool.

Lately, I've been working on Chrome extension CHash Thunder. Its aim is to update parts of the CloudHashing.com interface to provide the use with more information. Chrome's XPath feature is very handy, because it allows me to just store a bunch of JavaScript variables with XPath references to the user interface. If they'll every change the UI, I'll update those variables.

var TOP_MENU = '//*[@id="header"]/div/div/div[2]/div/div[1]/ul';
var INVESTMENT_BOX = '//*[@id="content"]/div/div[1]/div[3]/div[2]';
var LAST_ROUND = '//*[@id="content"]/div/table/tbody/tr[1]/td[1]';
var LAST_ROUND_DATE = '//*[@id="content"]/div/table/tbody/tr[1]/td[3]';
var BTC_BALANCE = '//*[@id="header"]/div/div/div[2]/div/div[1]/ul/li[3]';

The $x function can be used to get the element node.

var element = $x(TOP_MENU);

But... it only works in Chrome. So what about other browsers? What about jQuery? What about querying documents that resulted from an AJAX request?

To solve these problems, I've created a simple parser that will convert the XPath into a jQuery selector using regular expression parsing:

function $xp(xPath, $scope) {
    var selector = convertXPath(xPath);
    return $(selector, $scope);
}

function convertXPath(x) {

    //parse //*
    x = replace(x, '//\\*', '');

    //parse id
    x = replace(x, '\\[@id="([^"]*)"\\]', '#$1');

    //parse [1]
    x = replace(x, '\\[1\\]', ':first');

    //parse [n]
    x = replace(x, '\\[([0-9]+)\\]', ':eq($1)');

    //parse :eq's and lower 1
    var z = x.split(':eq(');
    x = z[0];
    if (z.length > 1) {
        for (var i = 1; i < z.length; i++) {
            var end = z[i].indexOf(')');
            var number = parseInt(z[i].substr(0, end)) - 1;
            x = x + ':eq(' + number + z[i].substr(end);
        }
    }

    //parse /
    x = replace(x, '/', ' > ');

    return x;
}

function replace(txt, r, w) {
 var re = new RegExp(r, "g");
 return txt.replace(re, w);
}

Here is an example that uses $xp to get the text of a hyperlink from an AJAX result:

var FIRST_RECORD_LINK = '//*[@id="rso"]/li[1]/div/h3/a';

$.ajax({
    type: "POST",
    url: '/Test.aspx',
    success: function (data, textStatus, request) {

        var $d = $('<div>').html(data);
        var $a = $xp(FIRST_RECORD_LINK, $d);
        alert($a.text());
    }
});

Improvements

2015-04-01: Chrome has a Copy CSS Path option. This expression can be used by jQuery without any problems.

  1. Kees C. Bakker says:

    Yep looks beter!

expand_less