F1e3ab214a976a39cfd713bc93deb10f

yup yup

getElementXPath = function(elm) {
  for (segs = []; elm && elm.nodeType == 1; elm = elm.parentNode) {
    if (elm.hasAttribute('id')) {
      segs.unshift('id("' + elm.getAttribute('id') + '")')
      return segs.join('/')
    }
    else if (elm.hasAttribute('class'))
      segs.unshift(elm.localName.toLowerCase() + '[@class="' + elm.getAttribute('class') + '"]')
    else {
      for (i = 1, sib = elm.previousSibling; sib; sib = sib.previousSibling)
        if (sib.localName == elm.localName) i++
      segs.unshift(elm.localName.toLowerCase() + '[' + i + ']')
    }
  }
  return segs.length ? '/' + segs.join('/') : null
}

Refactorings

No refactoring yet !

2e2f6dbd0462421a423c1ec458c4f0d7

latcho

March 2, 2011, March 02, 2011 06:21, permalink

No rating. Login to rate!

Hi thanks for this !
I was implementing this in Adobe Air's htmlcomponent.
What I discovered was that you stop the xpath tree immediatly when the element has an id.
But what if a bunch of containers in a table all share the same id ? Then I can never get the path to a unique "Prijs" node.
It isn't my html content, it was just a case I met.
So is it valid and possible (i'm no xpath connoisseur) to just disable line #5) // return segs.join('/')
so that we keep on going building the xpath tree when we have an id?
I did so but wonder or this will result in a valid xpath like I pasted below 2 lines (the td's en tr's have different indexes) ?

cheers,
Latcho

/html[1]/id("webshop")/id("container")/table[1]/tbody[1]/tr[4]/tr[3]/tr[3]/tr[2]/tr[2]/tr[1]/td[1]/id("productwrap")/id("productPrijs")/id("Prijs")/span[@class="Prijs"]

/html[1]/id("webshop")/id("container")/table[1]/tbody[1]/tr[3]/tr[2]/tr[2]/tr[1]/td[2]/td[2]/td[1]/id("productwrap")/id("productPrijs")/id("Prijs")/span[@class="Prijs"]
2e2f6dbd0462421a423c1ec458c4f0d7

latcho

March 2, 2011, March 02, 2011 10:32, permalink

No rating. Login to rate!

hey i fixed some bugs if the page uses multiple nodes with the same id's
it was only tested on safari's webkit so I don't know or the test with 'document.all[id]' is crossbrowser and always returns a collection if multiple of the same id's are there.

I added a test function getElementFromXPath(generatedPath) and it seems to work flawless now!
At least I know some more about xpath now :) So Ignore my previous post !
Cheers,
Latcho

function createElementXPath(elm) {
			for (segs = []; elm && elm.nodeType == 1; elm = elm.parentNode)
			{
				if (elm.hasAttribute('id')) {
						if (document.all[elm.getAttribute('id')].length == 1 || document.all[elm.getAttribute('id')].length == undefined) {
							segs.unshift('id("' + elm.getAttribute('id') + '")');
							return segs.join('/');
						} else {
							segs.unshift(elm.localName.toLowerCase() + '[@id="' + elm.getAttribute('id') + '"]');
						}
				} else if (elm.hasAttribute('class')) {
					segs.unshift(elm.localName.toLowerCase() + '[@class="' + elm.getAttribute('class') + '"]');
				} else {
					for (i = 1, sib = elm.previousSibling; sib; sib = sib.previousSibling) {
						if (sib.localName == elm.localName)  i++; 
					};       
					segs.unshift(elm.localName.toLowerCase() + '[' + i + ']');
				};
			}; 
			return segs.length ? '/' + segs.join('/') : null;
		};

function getElementFromXPath(path) {
	var evaluator = new XPathEvaluator();
	var result = evaluator.evaluate(path, document.documentElement, null,XPathResult.FIRST_ORDERED_NODE_TYPE, null);
	return  result.singleNodeValue;
};
D41d8cd98f00b204e9800998ecf8427e

la

March 7, 2011, March 07, 2011 16:26, permalink

No rating. Login to rate!

i wish i could delete stuff here...
this is the final version that doesn't uses the deprecated document.all to identify uniqe id's to shorten the expression

function createXPathFromElement(elm) { 
    var allNodes = document.getElementsByTagName('*'); 
    for (segs = []; elm && elm.nodeType == 1; elm = elm.parentNode) 
    { 
        if (elm.hasAttribute('id')) { 
                var uniqueIdCount = 0; 
                for (var n=0;n < allNodes.length;n++) { 
                    if (allNodes[n].hasAttribute('id') && allNodes[n].id == elm.id) uniqueIdCount++; 
                    if (uniqueIdCount > 1) break; 
                }; 
                if ( uniqueIdCount == 1) { 
                    segs.unshift('id("' + elm.getAttribute('id') + '")'); 
                    return segs.join('/'); 
                } else { 
                    segs.unshift(elm.localName.toLowerCase() + '[@id="' + elm.getAttribute('id') + '"]'); 
                } 
        } else if (elm.hasAttribute('class')) { 
            segs.unshift(elm.localName.toLowerCase() + '[@class="' + elm.getAttribute('class') + '"]'); 
        } else { 
            for (i = 1, sib = elm.previousSibling; sib; sib = sib.previousSibling) { 
                if (sib.localName == elm.localName)  i++; }; 
                segs.unshift(elm.localName.toLowerCase() + '[' + i + ']'); 
        }; 
    }; 
    return segs.length ? '/' + segs.join('/') : null; 
}; 

function lookupElementByXPath(path) { 
    var evaluator = new XPathEvaluator(); 
    var result = evaluator.evaluate(path, document.documentElement, null,XPathResult.FIRST_ORDERED_NODE_TYPE, null); 
    return  result.singleNodeValue; 
}
182e9001b22ca4f66f5f7dc9b04b2cdd

stijn

March 7, 2011, March 07, 2011 16:27, permalink

No rating. Login to rate!

i wish i could delete stuff here...
this is the final version that doesn't uses the deprecated document.all to identify uniqe id's to shorten the expression

function createXPathFromElement(elm) { 
    var allNodes = document.getElementsByTagName('*'); 
    for (segs = []; elm && elm.nodeType == 1; elm = elm.parentNode) 
    { 
        if (elm.hasAttribute('id')) { 
                var uniqueIdCount = 0; 
                for (var n=0;n < allNodes.length;n++) { 
                    if (allNodes[n].hasAttribute('id') && allNodes[n].id == elm.id) uniqueIdCount++; 
                    if (uniqueIdCount > 1) break; 
                }; 
                if ( uniqueIdCount == 1) { 
                    segs.unshift('id("' + elm.getAttribute('id') + '")'); 
                    return segs.join('/'); 
                } else { 
                    segs.unshift(elm.localName.toLowerCase() + '[@id="' + elm.getAttribute('id') + '"]'); 
                } 
        } else if (elm.hasAttribute('class')) { 
            segs.unshift(elm.localName.toLowerCase() + '[@class="' + elm.getAttribute('class') + '"]'); 
        } else { 
            for (i = 1, sib = elm.previousSibling; sib; sib = sib.previousSibling) { 
                if (sib.localName == elm.localName)  i++; }; 
                segs.unshift(elm.localName.toLowerCase() + '[' + i + ']'); 
        }; 
    }; 
    return segs.length ? '/' + segs.join('/') : null; 
}; 

function lookupElementByXPath(path) { 
    var evaluator = new XPathEvaluator(); 
    var result = evaluator.evaluate(path, document.documentElement, null,XPathResult.FIRST_ORDERED_NODE_TYPE, null); 
    return  result.singleNodeValue; 
}
6a4e52b221e70c4a90ea3a2420da0347

clonecd930

May 9, 2011, May 09, 2011 00:29, permalink

No rating. Login to rate!

Every man is the architect of his own fortunes.

Your refactoring





Format Copy from initial code

or Cancel