XPath: difference between dot and text()
Asked Answered
P

3

100

My question is about specifics of using dot and text() in XPath. For example, following find_element lines returns same element:

driver.get('http://stackoverflow.com/')

driver.find_element_by_xpath('//a[text()="Ask Question"]')
driver.find_element_by_xpath('//a[.="Ask Question"]')

So what is the difference? What are the benefits and drawbacks of using . and text()?

Pronounce answered 7/7, 2016 at 8:26 Comment(2)
My answer at https://mcmap.net/q/212703/-why-is-xpath-unclean-constructed-why-is-text-not-needed-in-predicate describes the difference between using text(), which selects a text node, and using an more general node selector (like .) in a comparison.Nasser
See also Testing text() nodes vs string values in XPath.Karalynn
A
162

There is a difference between . and text(), but this difference might not surface because of your input document.

If your input document looked like (the simplest document one can imagine given your XPath expressions)

Example 1

<html>
  <a>Ask Question</a>
</html>

Then //a[text()="Ask Question"] and //a[.="Ask Question"] indeed return exactly the same result. But consider a different input document that looks like

Example 2

<html>
  <a>Ask Question<other/>
  </a>
</html>

where the a element also has a child element other that follows immediately after "Ask Question". Given this second input document, //a[text()="Ask Question"] still returns the a element, while //a[.="Ask Question"] does not return anything!


This is because the meaning of the two predicates (everything between [ and ]) is different. [text()="Ask Question"] actually means: return true if any of the text nodes of an element contains exactly the text "Ask Question". On the other hand, [.="Ask Question"] means: return true if the string value of an element is identical to "Ask Question".

In the XPath model, text inside XML elements can be partitioned into a number of text nodes if other elements interfere with the text, as in Example 2 above. There, the other element is between "Ask Question" and a newline character that also counts as text content.

To make an even clearer example, consider as an input document:

Example 3

<a>Ask Question<other/>more text</a>

Here, the a element actually contains two text nodes, "Ask Question" and "more text", since both are direct children of a. You can test this by running //a/text() on this document, which will return (individual results separated by ----):

Ask Question
-----------------------
more text

So, in such a scenario, text() returns a set of individual nodes, while . in a predicate evaluates to the string concatenation of all text nodes. Again, you can test this claim with the path expression //a[.='Ask Questionmore text'] which will successfully return the a element.


Finally, keep in mind that some XPath functions can only take one single string as an input. As LarsH has pointed out in the comments, if such an XPath function (e.g. contains()) is given a sequence of nodes, it will only process the first node and silently ignore the rest.

Acima answered 25/1, 2017 at 21:55 Comment(2)
In example 3, what would be result for [text()="Ask Question"], will it return <a> or nothing.Truism
Finally, now I understand text() and contains(). Very helpful comment!Hammers
G
30

There is big difference between dot (".") and text() :-

  • The dot (".") in XPath is called the "context item expression" because it refers to the context item. This could be match with a node (such as an element, attribute, or text node) or an atomic value (such as a string, number, or boolean). While text() refers to match only element text which is in string form.

  • The dot (".") notation is the current node in the DOM. This is going to be an object of type Node while Using the XPath function text() to get the text for an element only gets the text up to the first inner element. If the text you are looking for is after the inner element you must use the current node to search for the string and not the XPath text() function.

For an example :-

<a href="something.html">
  <img src="filename.gif">
  link
</a>

Here if you want to find anchor a element by using text link, you need to use dot ("."). Because if you use //a[contains(.,'link')] it finds the anchor a element but if you use //a[contains(text(),'link')] the text() function does not seem to find it.

Hope it will help you..:)

Gracia answered 7/7, 2016 at 8:38 Comment(8)
I'm quite sure that I can match anchor with //a[contains(text(),'link')] as well as with //a[normalize-space(text())='link')] :) Anyway, thanks for answerPronounce
@Pronounce yeah off-course but not using text() directly..:)Gracia
@Andersson: You have a good point, but that only works if link is in the first text node child of a. In Saurabh's example, there may be a whitespace-only text node before the <img> element, in which case the XPath expressions in your comment wouldn't match the anchor. The reason is that the contains() and normalize-space() functions take the string value of the first node in the node-set that is their first argument.Nasser
@SaurabhGaur: You've got some good points, but it's not true that text() only selects text up to the first inner element. text() selects all text nodes (that are children of the context node, unless you specify a different axis). However if you pass the node set selected by text() to contains(), as you did, then it is converted to a string, by taking the string value of the first node in the node set. (w3.org/TR/xpath/#function-string)Nasser
As @Nasser has correctly pointed out, some parts of this answer are still wrong and should be amended. The most important misconception in the answer is that text() only selects the first text node, which is entirely untrue.Coda
@MathiasMüller: Probably one of us should post a correct answer. :-)Nasser
@Nasser True ;-). I just did that, tell me if something is inaccurate / missing.Coda
(-1) This answer is misleading. Read LarsH and Mathias' comments to understand how, or, better, see Mathias's answer and/or Lars' answer to another question and/or my answer to another question to better understand the subtleties here.Karalynn
H
-4

enter image description here The XPath text() function locates elements within a text node while dot (.) locate elements inside or outside a text node. In the image description screenshot, the XPath text() function will only locate Success in DOM Example 2. It will not find success in DOM Example 1 because it's located between the tags.

In addition, the text() function will not find success in DOM Example 3 because success does not have a direct relationship to the element . Here's a video demo explaining the difference between text() and dot (.) https://youtu.be/oi2Q7-0ZIBg

Hendecasyllable answered 30/7, 2019 at 0:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.