'Xpath expression error due to apostrophe in a String in robot framework
I encountered the below error in my robot framework script.
InvalidSelectorException: Message: invalid selector: Unable to locate an element with the xpath expression //ul[@id='xyz-ul']/li[contains(text(),'Épargne en vue d\'un objectif précis')] because of the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string '//ul[@id='xyzul']/li[contains(text(),'Épargne en vue d\'un objectif précis')]' is not a valid XPath expression.
I am trying to fetch the French data "Épargne en vue d'un objectif précis" from an excel and passing in an xpath to identify and click the element.
The element is a dropdown. This is one of the scenarios. I have many other such scenarios which are failing. Could someone help how to handle this?
Solution 1:[1]
XPath strings do not have escape sequences. This
//ul[@id='xyz-ul']/li[contains(text(),'Épargne en vue d\'un objectif précis')]
is just as invalid as this
//ul[@id='xyz-ul']/li[contains(text(),'Épargne en vue d'un objectif précis')]
would be.
It depends on the circumstances if you can mitigate this issue, or if you are out of luck.
In the context of a testing framework you might very well be out of luck, but you need to show more of your code to get a better answer.
There are two ways to get single quotes into a string in XPath.
Use double quotes for the string. Then you can use single quotes inside (and vice versa).
//ul[@id='xyz-ul']/li[contains(text(),"Épargne en vue d'un objectif précis")]When this is not feasible, like in your situation, because you never know whether a user-supplied value contains single- or double quotes, you must use the
concat()XPath function like this://ul[@id='xyz-ul']/li[contains(text(), concat('Épargne en vue d', "'", 'un objectif précis'))]
The second version looks difficult, but it can in fact be built reliably by splitting and joining the input string, like this
- Input string is
Épargne en vue d'un objectif précis - Splitting at
'givesÉpargne en vue dandun objectif précis - Joining with
', "'", 'givesÉpargne en vue d', "'", 'un objectif précis - Wrapping with
concat('and')givesconcat('Épargne en vue d', "'", 'un objectif précis'),
which is exactly the string you can put into an XPath expression with a placeholder, like this one:
${dropdown_selection_first_part_xpath} = //ul[@id='xyz-ul']/li[contains(text(),
${dropdown_selection_second_part_xpath} = )]
${dropdown_xpath} = //div[@id='xyz-widget']/div/div[2]/div[1]
${escaped_input_purpose_of_account} = (somehow to the 4 steps above)
${dropdown_selection_xpath} = catenate SEPARATOR= ${dropdown_selection_first_part_xpath} ${escaped_input_purpose_of_account} ${dropdown_selection_second_part_xpath}
This approach works for all inputs (empty string, strings with no quotes, strings with any mix of single- and double quotes) and always creates syntactically valid XPath expression that does what you expect.
Solution 2:[2]
As rightfully said in another answer, there's no quotes escaping in xpath. What you can do to workaround it, is to use the opposite quote type to surround the text string.
So for the sample in the question, this - double quotes - should do it:
//ul[@id='xyz-ul']/li[contains(text(),"Épargne en vue d'un objectif précis")]
Now, some of your test strings might have single quotes, others - double. Here'she a sample code how to construct the right one locator, per case:
${dropdown_selection_first_part_xpath} = //ul[@id='xyz-ul']/li[contains(text(), # no quote symbol
${dropdown_selection_second_part_xpath} = )] # no symbol here also
${dropdown_xpath} = //div[@id='xyz-widget']/div/div[2]/div[1]
# "Get Value" omitted for brevity, no change in it
Enter Value
click element xpath=${dropdown_xpath}
${input}= Get Value ${language}
# put the surrounding quotes based on the string's content - double quotes if it has a single one, single otherwise
${input}= Set Variable If "'" in """${input}""" "${input}" '${input}'
${dropdown_selection_xpath}= catenate SEPARATOR= ${dropdown_selection_first_part_xpath} ${input} ${dropdown_selection_second_part_xpath}
click element xpath=${dropdown_selection_xpath}
Finally, if you have test strings with both single and double quotes - it'll be much trickier, but still doable.
Solution 3:[3]
I've not tested this, but you could try:
//ul[@id='xyz-ul']/li[contains(text(),'Épargne en vue d'un objectif précis')]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Todor Minakov |
| Solution 3 | Bill Hileman |
