Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript evaluate XPATH within an element?

I am trying to get an element using document.evaluate() but also want to search only within a specific element. So for example:

const element = document.evaluate('.//p', ...); //I want this to return the Hello, World p element
<html>
  <body>
    <div id="someId">
      <p>Hello, World!<p>
    </div>
  </body>
</html>

Is there any way I could pass in the div with id someId into the evaluate to only search within that scope?

I know I could write the whole XPATH like .//div[@id="someId"]/p (Wouldnt work for my case) or do string concatenation but would like to find a cleaner way of doing it like passing the DOM element (or some object it contains) somewhere.

like image 377
WilliamTaco Avatar asked Oct 31 '25 05:10

WilliamTaco


2 Answers

This is precisely the purpose of the second argument of document.evaluate():

contextNode specifies the context node for the query (see the XPath specification). It's common to pass document as the context node.

const someId = document.getElementById('someId');

const result = document.evaluate('.//p', someId, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)

console.log(result.snapshotItem(0)); // Hello, World!
console.log(result.snapshotItem(1)); // null
<div id="someId">
  <p>Hello, World!</p>
</div>
<div>
  <p>Goodbye, World!</p>
</div>
like image 163
Guerric P Avatar answered Nov 01 '25 18:11

Guerric P


You can also use document for the contextNode, using the parent id within the query (like you asked). Like this:

const snapshotType = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
const result1 = document.evaluate('.//div[@id="someId"]//p', document, null, snapshotType);

console.log(`result1 contains ${result1.snapshotLength} element, namely`, result1.snapshotItem(0))

//alternatively search for the actual text
const result2 = document.evaluate('.//p[contains(text(), "Hello")]', document, null, snapshotType);

console.log(`result2 contains ${result2.snapshotLength} element, namely`, result2.snapshotItem(0));

// finally, if the element order is fixed, you can take the first one
const result3 = document.evaluate('(.//p)[1]', document, null, snapshotType);
console.log(`result3 contains ${result3.snapshotLength} element, namely`, result3.snapshotItem(0));
<div id="someId">
  <p>Hello, World!</p>
</div>
<div>
  <p>Goodbye, World!</p>
</div>
<div>
  <p>And I left</p>
</div>
like image 43
KooiInc Avatar answered Nov 01 '25 19:11

KooiInc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!