Selenium WebDriver kullanarak JavaScript ile XPath üzerinden bir elementi almak için bir yol var mı?


Aşağıdakine benzer bir şey arıyorum:

getElementByXpath(//html[1]/body[1]/div[1]).innerHTML

JS kullanarak elementlerin innerHTML'sini almam gerekiyor (bunu Selenium WebDriver/Java'da kullanmak için, çünkü WebDriver bunu kendisi bulamıyor), ama nasıl?

ID özniteliğini kullanabilirim, ama tüm öğelerin ID özniteliği yok.

Cevap #1

document.evaluate öğesini kullanabilirsiniz:

Bir XPath ifade dizisini değerlendirir ve mümkünse belirtilen türde bir sonuç döndürür.

W3 tarafından standartlaştırılmıştır ve tamamen belgelenmiştir: https://developer.mozilla.org/en-US/docs/Web/API/Document.evaluate

function getElementByXpath(path) {
  return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}

console.log( getElementByXpath("//html[1]/body[1]/div[1]") );
<div>foo</div>

https://gist.github.com/yckart/6351935

Mozilla geliştirici ağında ayrıca harika bir giriş bulunmaktadır: https://developer.mozilla.org/en-US/docs/Introduction_to_using_XPath_in_JavaScript#document.evaluate

Alternatif versiyon, XPathEvaluator kullanılarak:

function getElementByXPath(xpath) {
  return new XPathEvaluator()
    .createExpression(xpath)
    .evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE)
    .singleNodeValue
}

console.log( getElementByXPath("//html[1]/body[1]/div[1]") );
<div>foo/bar</div>

Cevap #2

Chrome Geliştirici Araçlarında aşağıdakileri çalıştırabilirsiniz:

$x("some xpath")

Cevap #3

Xpath ve javascript kullanarak bir WebElement'i tanımlamak için, bir xpath ifadesini değerlendiren ve bir sonuç döndüren evaluate() yöntemini kullanmanız gerekir.


document.evaluate()

document.evaluate() bir XPath ifadesine ve verilen diğer parametrelere dayalı olarak bir XPathResult döner.

Sözdizimi şudur:

var xpathResult = document.evaluate(
  xpathExpression,
  contextNode,
  namespaceResolver,
  resultType,
  result
);

Nerede :

  • xpathExpression: Değerlendirilecek XPath'i temsil eden dize.
  • contextNode: Sorgu için bağlam düğümünü belirtir. Yaygın uygulama, bağlam düğümü olarak document geçirmektir.
  • namespaceResolver: Herhangi bir ad alanı önekine geçirilecek ve bu önekle ilişkili ad alanı URI'sını temsil eden bir dize döndürmesi gereken işlev. Bu, öneklerin belge ile eşleştirilebilmesi için XPath içinde çözümlenmesi amacıyla kullanılacaktır. HTML belgeleri için veya hiçbir ad alanı öneki kullanılmadığında null yaygındır.
  • resultType: XPathResult yapıcısının adlandırılmış sabit özelliklerini kullanarak döndürülecek XPathResult türüne karşılık gelen bir tamsayı, örneğin XPathResult.ANY_TYPE, ve bu özellikler 0'dan 9'a kadar olan tamsayılara karşılık gelir.
  • result: Sonuçlar için kullanılacak mevcut bir XPathResult. null en yaygın olandır ve yeni bir XPathResult oluşturur

Gösteri

Bir örnek olarak, Google Ana Sayfasındaki Arama Kutusu, xpath ile //*[@name='q'] olarak benzersiz şekilde tanımlanabilir ve ayrıca google-chrome-devtools Console kullanılarak aşağıdaki komut ile de tanımlanabilir:

$x("//*[@name='q']")

Anlık Görüntü:

Aynı öğe, document.evaluate() ve xpath ifadesi kullanılarak da şu şekilde tanımlanabilir:

document.evaluate("//*[@name='q']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

Anlık Görüntü:

Cevap #4

Chrome komut satırı API'sinden $x gibi bir şey (birden fazla öğe seçmek için) denemek için:

var xpath = function(xpathToExecute){
  var result = [];
  var nodesSnapshot = document.evaluate(xpathToExecute, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
  for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ ){
    result.push( nodesSnapshot.snapshotItem(i) );
  }
  return result;
}

Bu MDN genel bakışı yardımcı oldu: https://developer.mozilla.org/en-US/docs/Introduction_to_using_XPath_in_JavaScript

Cevap #5

Birçok tarayıcıda $x(xPath) konsol yerleşik olarak bulunsa da, işte JavaScript'te XPath kullanmaya giriş bölümünden, komut dosyalarında kullanıma hazır, faydalı ama sabit kodlu parçacıkların bir derlemesi:

Anlık Görüntü

Bu, xpath sonuç kümesinin tek seferlik bir anlık görüntüsünü verir. DOM değişikliklerinden sonra veriler eski olabilir.

const $x = xp => {
  const snapshot = document.evaluate(
    xp, document, null, 
    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
  );
  return [...Array(snapshot.snapshotLength)]
    .map((_, i) => snapshot.snapshotItem(i))
  ;
};

console.log($x('//h2[contains(., "foo")]'));
<h2>foo</h2>
<h2>foobar</h2>
<h2>bar</h2>

İlk sıralı düğüm

const $xOne = xp => 
  document.evaluate(
    xp, document, null,
    XPathResult.FIRST_ORDERED_NODE_TYPE, null
  ).singleNodeValue
;

console.log($xOne('//h2[contains(., "foo")]'));
<h2>foo</h2>
<h2>foobar</h2>
<h2>bar</h2>

Yineleyici

Ancak, belgenin yinelemeler arasında değiştirildiğini (belge ağacının değiştirildiğini) unutmayın; bu durum yinelemeyi geçersiz kılar ve XPathResult'in invalidIteratorState özelliği true olarak ayarlanır ve bir NS_ERROR_DOM_INVALID_STATE_ERR istisnası fırlatılır.

function *$xIter(xp) {
  const iter = document.evaluate(
    xp, document, null, 
    XPathResult.ORDERED_NODE_ITERATOR_TYPE, null
  );

  for (;;) {
    const node = iter.iterateNext();
    
    if (!node) {
      break;
    }
    
    yield node;
  }
}

// dump to array
console.log([...$xIter('//h2[contains(., "foo")]')]);

// return next item from generator
const xpGen = $xIter('//h2[text()="foo"]');
console.log(xpGen.next().value);
<h2>foo</h2>
<h2>foobar</h2>
<h2>bar</h2>

Cevap #6

DOM üzerinde bir XPath ifadesi çalıştırmak için javascript'in document.evaluate özelliğini kullanabilirsiniz. Bence bu, IE 6'ya kadar tarayıcılarda bir şekilde destekleniyor.

MDN: https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate

IE bunun yerine selectNodes metodunu destekler.

MSDN: https://msdn.microsoft.com/en-us/library/ms754523(v=vs.85).aspx

İlgili makaleler