XPath Question...

Subscribe to XPath Question... 45 posts, 7 voices

 
Gnintendo Scriptwright

I'm currently using this to get an xpath node:
function getXPathNode(_xPath){
return document.evaluate(_xPath,document,null,9,null).singleNodeValue}

Is there another way I can do that to just return elements by their XPath because that only works sometimes with some elements, I want it to just be able to work with any XPath I set it to like this:
var *namehere*=getXPathNode("*XPathHere*")

Thanks in advance.

 
grey Scriptwright

I use the same function and I cant remembering having any problems.. except from giving it a xPath that didn't match what I wanted...

Might it be that your xPath match more than one element? '

Think that the function will return the first element matching your xPath and then exit.. this can give some "odd" behaviors sometime if you doesn't keep it in mind ;-)

Can you give some example of xPaths and html that fails for you?

 
Gnintendo Scriptwright

It shouldn't matter, what if I wanted to return the multiple elements, besides, the way I got the xpath I'm 100% sure it only applied to the XPath I wanted it to return.

Can't there be some more general function for returning an element, one that works more often?

 
JoeSimmons Scriptwright

// XPath but the array returned is a normal array[i] array
function $x(p, context) {
  if (!context) context = document;
  var i, arr = [], xpr = document.evaluate(p,context,null,6,null);
  for (i = 0; item = xpr.snapshotItem(i); i++) {arr.push(item);}
  if(arr.length==1) {return arr[0];} else {return arr;}
}

With this code, if your xpath has only 1 result (e,g,. say if you did "//*[@id='someID']") your result wont be an array, but if it has more than 1 result, it will be.

 
grey Scriptwright

the ".singleNodeValue" makes it return just a single value if you want to get multiple elements you'll have to do something like this

var xSearch = "//a";

var allMatches = document.evaluate(
				xSearch, document, null,
				XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null
			);

for (var i = 0; i < allMatches.snapshotLength; i++) 
	GM_log('Found link to: ' + allMatches.snapshotItem(i).href);

Or using the XPath helper. See http://wiki.greasespot.net/Code_snippets#XPath_...

I'm using either the getXPathNode (as in the example I gave you in this post http://userscripts.org/forums/1/topics/9159#pos...) or something like the code above (depending on if I'm grabbing a single element or mutiples) and I don't have any bigger problems getting the element/elements I wanted..

Heres a addon for testing your xPaths in http://xpath.alephzarro.com/ (you can also use it to get the xPath to a element),

 
Gnintendo Scriptwright

Sigh.

All your examples are incompatible with the previous example.

Do it EXACTLY like the previous one except with multiple, because now your getting this found link to crap :/

 
JoeSimmons Scriptwright

If mine doesn't work then you need to explain what you want more clearly.

If you wanted to have 2 XPaths in one query, you could do:

var E = document.evaluate("//a | //div", document, null, 6, null);

 
Gnintendo Scriptwright

Sorry, I missed your reply earlier, thanks.

 
Gnintendo Scriptwright

OK, I think I know why I can't hide some things I got with XPath, it must be my hiding function :s

function toggleHidden(_node){
if(_node.style.display !='none')
_node.style.display='none'
else
_node.style.display=''}

Then after that I hide something like this:

var toHide=$x("/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[49]")
toggleHidden(toHide)

But that won't hide if if I try to do multiple XPaths in the same one it won't work at all, if I declare a second var and try to toggle it only the first one will toggle.

How do I change it so it works with more than one?

 
JoeSimmons Scriptwright

Just use this

// XPath but the array returned is a normal array[x]
function $x(p, type) {
  var i, arr = [], t = type || 6, xpr = document.evaluate(p,document,null,t,null);
  for (i = 0; item = xpr.snapshotItem(i); i++) {arr.push(item);}
  return arr;
}

then do this

var toHide=$x("/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[49]");
toggleHidden(toHide[0]);

 
Gnintendo Scriptwright

Now it'll only hide the second thing I try to add to the toHide:
/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[48]

I also want to add this:
/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[47]

 
JoeSimmons Scriptwright

var toHide=$x("/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[47] | /html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[48]");
for(var i=0; i<toHide.length; i++) {toggleHidden(toHide[i]);}

 
Gnintendo Scriptwright

with this:

var toHide=$x("/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[49] | /html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[47] | /html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[48]");
for(var i=0; i<tohide>

This one won't hide:

/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table[4]/tbody/tr[47]

 
Gnintendo Scriptwright

Disregard previous reply but I have a question.

Any time I hide anything like I have been here, and it works for me, for some other people it doesn't work at all.

Do you have any idea why?

 
Gnintendo Scriptwright

Bump

 
JoeSimmons Scriptwright

No, because I have no idea what you're testing this on.

 
Gnintendo Scriptwright

A php-bb forum, it works FINE for me, but not for some other people.

 
JoeSimmons Scriptwright

People might have different table arrangements. You need to be more specific on the xpath.
Give me the site and a screenshot with an arrow pointing to what you want to hide and I'll try it.

 
Gnintendo Scriptwright

Before you accuse me of advertising you WILL have to register....

Also, since you've pointed me in the right direction, I'm going to attempt to hide it myself.

 
Aquilax Scriptwright

I know that there are some add-ons to get the xpath of the elements, you can try one of them:

xpath add-ons

 
JoeSimmons Scriptwright

I don't care if you're advertising, just give me the site lol and tell me what you want to hide.

 
Gnintendo Scriptwright

OK, I got it all working for everybody but when I tried to add one more element (this will be the last one) it doesn't hide it while it still hides all the others:
/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table/tbody/tr[50]

So add the above XPath to this:

function $x(p, type) {
  var i, arr = [], t = type || 6, xpr = document.evaluate(p,document,null,t,null);
  for (i = 0; item = xpr.snapshotItem(i); i++) {arr.push(item);}
  return arr;}
function toggleHidden(_node){
_node.style.display='none'}
var toHide=$x("/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table/tbody/tr[49]|/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table/tbody/tr[47]|/html/body/table/tbody/tr/td/table[3]/tbody/tr/td/table/tbody/tr[48]");
for(var i=0; i<tohide>

Also, is there a way to make the toggleHidden >delete< the element rather than hide it?

 
JoeSimmons Scriptwright

Yeah.

function toggleHidden(_node) {
if(_node) {_node.parentNode.removeChild(_node);}
}

This is a function by me to remove nodes through xpath...

// Remove nodes through xpath by JoeSimmons
// Syntax example: removeXP("img[contains(@src, 'ad.jpg')]");
function removeXP(xp) {
var i,x,XP=document.evaluate(xp,document,null,6,null);
for(i=0; i<XP.snapshotLength; i++) {x=XP.snapshotItem(i);x.parentNode.removeChild(x);}
}

And this is a function by me to remove an id...

// Remove element by id by JoeSimmons
// Syntax example: removeElemById("gbar");
function removeElemById(e) {
var _e = document.getElementById(e);
if(_e && _e.parentNode) {
_e.parentNode.removeChild(_e);
return true;
}
else {return false;}
}

 
Gnintendo Scriptwright

Thanks!

Works, now how do I get adding that other XPath to work?

 
JoeSimmons Scriptwright

Add another pipe | to the xpath query and put your other query I believe.