Using XPATH to search text containing
XmlSearchXpathSeleniumXml Problem Overview
I use XPather Browser to check my XPATH expressions on an HTML page.
My end goal is to use these expressions in Selenium for the testing of my user interfaces.
I got an HTML file with a content similar to this:
<tr> <td>abc</td> <td> </td> </tr>
I want to select a node with a text containing the string "
".
With a normal string like "abc" there is no problem. I use an XPATH similar to //td[text()="abc"]
.
When I try with an an XPATH like //td[text()=" "]
it returns nothing. Is there a special rule concerning texts with "&
" ?
Xml Solutions
Solution 1 - Xml
It seems that OpenQA, guys behind Selenium, have already addressed this problem. They defined some variables to explicitely match whitespaces. In my case, I need to use an XPATH similar to //td[text()="${nbsp}"]
.
I reproduced here the text from OpenQA concerning this issue (found here):
> HTML automatically normalizes
> whitespace within elements, ignoring
> leading/trailing spaces and converting
> extra spaces, tabs and newlines into a
> single space. When Selenium reads text
> out of the page, it attempts to
> duplicate this behavior, so you can
> ignore all the tabs and newlines in
> your HTML and do assertions based on
> how the text looks in the browser when
> rendered. We do this by replacing all
> non-visible whitespace (including the
> non-breaking space "
") with a
> single space. All visible newlines
> (<br>
, <p>
, and <pre>
formatted
> new lines) should be preserved.
>
> We use the same normalization logic on
> the text of HTML Selenese test case
> tables. This has a number of
> advantages. First, you don't need to
> look at the HTML source of the page to
> figure out what your assertions should
> be; "
" symbols are invisible
> to the end user, and so you shouldn't
> have to worry about them when writing
> Selenese tests. (You don't need to put
> "
" markers in your test case
> to assertText on a field that contains
> "
".) You may also put extra
> newlines and spaces in your Selenese
> <td>
tags; since we use the same
> normalization logic on the test case
> as we do on the text, we can ensure
> that assertions and the extracted text
> will match exactly.
>
> This creates a bit of a problem on
> those rare occasions when you really
> want/need to insert extra whitespace
> in your test case. For example, you
> may need to type text in a field like
> this: "foo
". But if you simply
> write <td>foo </td>
in your
> Selenese test case, we'll replace your
> extra spaces with just one space.
>
> This problem has a simple workaround.
> We've defined a variable in Selenese,
> ${space}
, whose value is a single
> space. You can use ${space}
to
> insert a space that won't be
> automatically trimmed, like this:
> <td>foo${space}${space}${space}</td>
.
> We've also included a variable
> ${nbsp}
, that you can use to insert
> a non-breaking space.
>
> Note that XPaths do not normalize
> whitespace the way we do. If you need
> to write an XPath like
> //div[text()="hello world"]
but the
> HTML of the link is really
> "hello world
", you'll need to
> insert a real "
" into your
> Selenese test case to get it to match,
> like this:
> //div[text()="hello${nbsp}world"]
.
Solution 2 - Xml
I found I can make the match when I input a hard-coded non-breaking space (U+00A0) by typing Alt+0160 on Windows between the two quotes...
//table[@id='TableID']//td[text()=' ']
worked for me with the special char.
From what I understood, the XPath 1.0 standard doesn't handle escaping Unicode chars. There seems to be functions for that in XPath 2.0 but it looks like Firefox doesn't support it (or I misunderstood something). So you have to do with local codepage. Ugly, I know.
Actually, it looks like the standard is relying on the programming language using XPath to provide the correct Unicode escape sequence... So, somehow, I did the right thing.
Solution 3 - Xml
Try using the decimal entity  
instead of the named entity. If that doesn't work, you should be able to simply use the unicode character for a non-breaking space instead of the
entity.
(Note: I did not try this in XPather, but I did try it in Oxygen.)
Solution 4 - Xml
As per the HTML you have provided:
<tr>
<td>abc</td>
<td> </td>
</tr>
To locate the node with the string
you can use either of the following [tag:xpath] based solutions:
-
Using
text()
:"//td[text()='\u00A0']"
-
Using
contains()
:"//td[contains(., '\u00A0')]"
However, ideally you may like to avoid the NO-BREAK SPACE character and use either of the following Locator Strategies:
-
Using the parent
<tr>
node andfollowing-sibling
:"//tr//following-sibling::td[2]"
-
Using
starts-with()
:"//tr//td[last()]"
-
Using the preceeding
<td>
node andfollowing
node and
following-sibling`:"//td[text()='abc']//following::td[1]"
Reference
You can find a relevant detailed discussion in:
tl; dr
Solution 5 - Xml
Bear in mind that a standards-compliant XML processor will have replaced any entity references other than XML's five standard ones (&
, >
, <
, '
, "
) with the corresponding character in the target encoding by the time XPath expressions are evaluated. Given that behavior, PhiLho's and jsulak's suggestions are the way to go if you want to work with XML tools. When you enter  
in the XPath expression, it should be converted to the corresponding byte sequence before the XPath expression is applied.
Solution 6 - Xml
Search for
or only nbsp
- did you try this?
Solution 7 - Xml
I cannot get a match using Xpather, but the following worked for me with plain XML and XSL files in Microsoft's XML Notepad:
<xsl:value-of select="count(//td[text()=' '])" />
The value returned is 1, which is the correct value in my test case.
However, I did have to declare nbsp as an entity within my XML and XSL using the following:
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
I'm not sure if that helps you, but I was able to actually find nbsp using an XPath expression.
Edit: My code sample actually contains the characters ' ' but the JavaScript syntax highlight converts it to the space character. Don't be mislead!