1

I have read the answers to these three questions about case insensitive XPath searches:

case insensitive xpath contains() possible?

Using upper-case and lower-case xpath functions in selenium IDE

XPath find text in any text node

When I try the XPath 1 and 2 solutions suggested there in Chrome and Firefox none of them work (good).

I am looking for a word that currently is written with initial upper case latter and the rest lower case (like this: Example) but translate(.,'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLOMNOPQRSTUVWXYZ') can't find the string at all when using at least two letters. I have tried EX (2 hits, none of them on Example), ex (0 hits), Ex (0), xa (0), XAM (0)

Changing the translate order to translate(.,'ABCDEFGHIJKLOMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') results in EX (0 hits), ex (0), Ex (0), xamp (1 hit - correct!! But I have to exclude the initial letter which is unacceptable), xa (0)

Trying the XPath 2.0 solutions suggested in the answers linked above returns these errors:

XPath 2.0

I want to perform a case insensive search for this XPath

//div[@class='nav group']//a[contains(text(), 'Example')]

How do I do that?

d-b
  • 695
  • 3
  • 14
  • 43
  • I'm not 100% sure I understand your question. If you want to find the exact case match, then do not use translate. If you want to find the word REGARDLESS of case, which you imply, then force all text to either all uppercase or all lowercase, then compare the result to the same with the text - EXAMPLE or example, not Example. – Bill Hileman Jun 10 '19 at 18:37

3 Answers3

2

Here is the xpath.

//div[@class='nav group']//*[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='example']

Chrome: enter image description here Console: enter image description here

supputuri
  • 13,644
  • 2
  • 21
  • 39
  • You changed my ``a`` to a ``span`` which broke it. Was it on purpose? Anyway, using ``//div[@class='nav group']//a[translate('Example','abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')]`` I get 54 hits where I should get one. It matches all other items in the list ``Example`` is in. Any ideas why? My original XPath only matches the item I am interested in. – d-b Jun 08 '19 at 16:03
  • Can you please check with my updated answer. I was just checking with the span... – supputuri Jun 08 '19 at 22:29
  • This is the only one works for me across all other StackOverflow answers. – Tim Yao May 04 '21 at 10:07
1

Sadly, 12 years after XPath 2.0 was published, and despite all the known limitations of XPath 1.0, the browser vendors have still not updated their XPath implementations.

There are third-party implementations available (Saxon-JS supports XPath 3.1, for example) so that's one possible way forward.

But so long as you're only using the English alphabet, the XPath 1.0 workaround using

contains(translate(., 'abcde...', 'ABCDE...'), "EXAMPLE")

should work fine.

You can either translate everything to upper case and test against an upper-case search term, or translate everything to lower case and test against a lower-case search term.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Doesn't work. ``$x("//div[@class='nav group']//a[contains(translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'Example')]")`` doesn't match anything. What is the purpose with the initial ``., ``? – d-b Jun 08 '19 at 16:08
  • Read what I wrote. If you convert it to upper case then it's going to contain "EXAMPLE", not "Example". Using "." rather than "text()" is the preferred way to get the string value of the context element. – Michael Kay Jun 08 '19 at 19:03
0

Here are two functions I use which might come in handy. You don't actually have to specify the entire alphabet when doing a translate, it only needs the letters of the word you're searching for:

public String translate(String text) {
    return "translate(text(),'" + text.toUpperCase() + 
           "','" + text.toLowerCase() + "')='" + text.toLowerCase() + "'";
}

public String translateNormalized(String text) {
    return "translate(normalize-space(text()),'" + text.toUpperCase() + 
           "','" + text.toLowerCase() + "')='" + text.toLowerCase() + "'";
}

I use these functions to build an xpath locator, i.e.:

String xpath = "//a[" + translateNormalized("Click here for more info") + "]";
Bill Hileman
  • 2,798
  • 2
  • 17
  • 24
  • How do I use these functions in a service that expects an XPath as "input"? – d-b Jun 10 '19 at 19:44
  • For one thing, they might need to be modified to use contains instead of equals, I'll assume you know how to do that. Like the example I have at the end, after changing the method to contains, you would assign to a string `"//div[@class='nav group']//a[" + translate("Example") + "]"` and pass that as the xpath locator. – Bill Hileman Jun 10 '19 at 20:13
  • But again, if you are looking for an EXACT match in case of "Example" then you should not use translate at all because it will ignore case and return all instances of "example" regardless of case. – Bill Hileman Jun 10 '19 at 20:17