Search code examples
htmlseleniumselenium-webdriverxpathwebdriver

What is the Correct XPath to Identify Element with Text Occuring Minimum Number of Times?


I'm trying to identify an element that has certain text but I only want to identify the element if the desired text occurs a specific number of times.

For example, imagine we have the following two HTML snippets on the same page:

Snippet 1:

<span id="price">

$36.46

<span>
($0.38 /  Count)
</span>
  
</span>

Snippet 2:

<span id="price">$38.38</span>

I could identify both elements using the XPath: .//span[contains(text(),'$')] However, I only want to identify the element if it (or any descendant of span element) contain at least two instances of the character: $

In above example, it would only identify the first snippet because the second snippet only contains one instance of $, not two.

What is the correct XPath syntax to use?


Solution

  • You can use the XPath //span[count(.//text()[contains(., "$")]) >= 2]

    This is a moderately complicated XPath, so to explain it some by expanding outwards:

    .//text()[contains(., "$")]

    Select all text elements descending from the current node whose self contains "$".

    count(.//text()[contains(., "$")])

    Count the number of text elements descending from the current node whose self contains "$".

    //span[count(.//text()[contains(., "$")]) >= 2]

    Select all span elements with two or more text descendants whose self contains "$"

    As a caveat, this only works if the dollar sign is in two different text elements. If you want to include the span in this example:

    <span>
        $$
        <span>
        foo
        </span>
    </span>
    

    ...then you'll need a different approach:

    //span[string-length(.) - string-length(translate(., "$", "")) >= 2]

    This predicate compares the string length of the span to the string length of the same span with all "$" characters removed.