Search code examples
xpathgreasemonkeydocument.evaluate

Why does XPath exaluate gives snapshotLength = 1 for /html/body and 0 for /html/body/div[3]/div[3]/div/div[6]/div[2]/div/div/div?


Could you tell me why XPath exaluate gives

  snapshotLength = 1 for /html/body 

and 0 for

  /html/body/div[3]/div[3]/div/div[6]/div[2]/div/div/div

The longer XPath is for real, calculated by Firepath for an object on this page

http://srv1.yogh.io/#mine:height:0

I run the following script in Greasemonkey.

// ==UserScript==
// @name        xpath greasemonkey
// @namespace   bbb
// @description f
// @match       http://srv1.yogh.io/#mine:height:0
// @version     1
// @grant       none
// ==/UserScript==
var allLinks, thisLink;
console.log("dfsdsdsdfg");
allLinks = document.evaluate(
     "/html/body/div",
     document,
     null,
     XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
     null);
// for (var i = 0; i < allLinks.snapshotLength; i++) {
//   thisLink = allLinks.snapshotItem(i);
 // console.log("found");
// }
console.log(allLinks.snapshotLength)


// /html/body/div[3]/div[3]/div/div[6]/div[2]/div/div/div
// ---
// UPDATED userscript

// ==UserScript==
// @name        xpath greasemonkey2
// @namespace   bbb
// @description f
// @match       http://srv1.yogh.io/#mine:height:0
// @version     1
// @grant       none
// ==/UserScript==

window.setTimeout(function() {
  var allLinks, thisLink;
  console.log("dfsdsdsdfg");
   
  allLinks = document.evaluate(
       "/html/body/div[3]/div[3]/div/div[6]/div[2]/div/div/div",
       document,
       null,
       XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
       null);
  if(allLinks.snapshotLength) {
    console.log(allLinks.snapshotLength);
    console.log(allLinks.snapshotItem(0).innerHTML)
  } else {
    console.log("Bother...");
    console.log(allLinks.snapshotLength)
  }
}, 15000);

function myFunction() {
    if (window.top != window.self)  {
      alert("This window is not the topmost window! Am I in a frame?");
        document.getElementById("demo").innerHTML = "This window is not the topmost window! Am I in a frame?";
    } else { 
       alert("This window is the topmost window! Am I in a frame?");
        document.getElementById("demo").innerHTML = "This window is the topmost window!";
    } 
}
var input=document.createElement("input");
input.type="button";
input.value="GreaseMonkey Button";
input.onclick = myFunction;
document.body.appendChild(input); 

I would like the code to find the XPathed DIV object on web page highlight it and return via console.log as:

<div class="gwt-Label">2083236893</div>

for postprocessing to read string 2083236893 via .innerText or .innerHTML

Any idea or any working script demo to work in GM or in Fiddle?


Solution

  • Your XPath is actually OK, and should work if you enter it directly in your browser's console. The problem is that the content of the Blockchain web page is generated dynamically by a script, so the node you are looking for doesn't exist at the time your userscript is executed.

    You need to delay your code from running until after the page has finished loading. The @run-at userscript metadata directive is supposed to achieve this, but either it's broken in GreaseMonkey v4, or the Blockchain script takes too long time to run and you need to delay your userscript even longer. Either way, wrapping your code in setTimeout() is a simple way to do the trick (detecting when the other script has finished would be more elegant):

    // ==UserScript==
    // @name        xpath greasemonkey
    // @namespace   bbb
    // @description f
    // @match       http://srv1.yogh.io/
    // @version     1
    // @grant       none
    // ==/UserScript==
    
    window.setTimeout(function() {
      var allLinks, thisLink;
      console.log("dfsdsdsdfg");
      allLinks = document.evaluate(
           "/html/body/div[3]/div[3]/div/div[6]/div[2]/div/div/div",
           document,
           null,
           XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
           null);
      if(allLinks.snapshotLength) {
        console.log(allLinks.snapshotItem(0).innerHTML);
      } else {
        console.log("Bother...");
      }
    }, 5000);

    (Note I also had to change your @match directive to get Greasemonkey to run the script on the right page).