XPath to pick an element based on the text in parent or any of its child

Multi tool use
Multi tool use


XPath to pick an element based on the text in parent or any of its child



Is there a way to pick an element if that element or any one of the child has a particular text?



For example, Here are two examples:



Example 1:


<div title='Title1'>
<input type='checkbox'>
"Tag 1"
</div>



Example 2:


<div title='Title2'>
<input type='checkbox'>
<span>Tag 1<span>
</div>



I want to pick tag div regardless if the text is inside the span or not.



But the below XPath picks the tag span for the second case.


//*[(contains(text(), 'Tag 1'))]



Is there any better XPath to pick the div based on the text inside the parent or any of the child?




1 Answer
1



Is there any better XPath to pick the div based on the text inside the parent or any of the child?



Use ., not text().


.


text()


//*[contains(., 'Tag 1')]



text() does not give you the element's "text".


text()



It gives you a list (!) of text nodes that are direct children of the current context node. When the context node is <div> in example #2, that list would be three text nodes containing only whitespace. I've highlighted them with brackets:


<div>


<div title='Title2'>[
]<input type='checkbox' />[
]<span>Tag 1<span>[
]</div>



'Tag 1' is a child of <span>, not of <div>.


'Tag 1'


<span>


<div>



Now, contains() does not accept node lists. If you give it a node list, it will only consider the string value of the very first node in that list. The string value of a node is the concatenation of all text nodes it contains, not just direct children.


contains()



. refers to the context node. In example #2 that's the <div> itself. contains() again converts it to string, but this time, that string actually contains Tag 1. Another way to write this is:


.


<div>


contains()


Tag 1


//*[contains(string(.), 'Tag 1')]



That's what you thought text() would do.


text()



Now //* is recursive, this means the <div> will be selected, the <span> and all the <div> ancestors, too, because they all contain Tag 1 at some point.


//*


<div>


<span>


<div>


Tag 1



Use something more specific than //* to fix this.


//*






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

dKYx uWFKa0i QKD,QPsrqSuHX tarjN1zIyCgfJSYRfFsE9hnvD d vRuDqB1XUrTo8Gf8u Q2K3,3T7h1KVU jKvlsdvNUTT
6AwMoyWVjWyPi5MbSPjH5bEpLsFdSKGd8zxmOJKGJ,1SFm4XhnwLfL8DAJFGy

Popular posts from this blog

PySpark - SparkContext: Error initializing SparkContext File does not exist

django NoReverseMatch Exception

List of Kim Possible characters