19

Here is the XPath I'm trying to use:

//div[contains(@class='xyz ng-binding ng-scope') and not(contains(@class = 'ng-hide'))]

I'm not sure what the correct syntax for this is. Basically the HTML looks like like:

class="xyz ng-binding ng-scope typeA ng-hide"
class="xyz ng-binding ng-scope typeB ng-hide"

I want to select the case where the HTML is either typeA or typeB but does not have ng-hide.

Stefano Sanfilippo
  • 32,265
  • 7
  • 79
  • 80
Matt
  • 225
  • 2
  • 3
  • 7

4 Answers4

27

You could do something like this:

//div[(contains(@class,'typeA') or contains(@class,'typeB')) and not(contains(@class,'ng-hide'))]

You should also take a look at How can I match on an attribute that contains a certain string? to see why the contains() above might not match exactly what you're intending.

For example, to truly match what you are intending, you could use:

//div[(contains(concat(' ',@class,' '),' typeA ') or contains(concat(' ',@class,' '),' typeB ')) and not(contains(concat(' ',@class,' '),' ng-hide '))]

It's much easier in XPath 2.0, but I'm not sure if qtp supports it. If you could make concat(' ',@class,' ') a variable, you could clean up the XPath too.

Here's a 2.0 example just in case:

//div[tokenize(@class,'\s')=('typeA','typeB') and not(tokenize(@class,'\s')='ng-hide')]
Community
  • 1
  • 1
Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
5

In your question, the syntax is incorrect as Michael Kay has pointed out.

If I understand your question correctly, you want to select a class that contains "xyz ng-binding ng-scope" but not "ng-hide" regardless if it contains "typeA", "typeB" or not.

I would use something like this:

//div[contains(normalize-space(@class), 'xyz ng-binding ng-scope') and not(contains(@class, 'ng-hide'))]

I often find that the spaces cause problem in this situation. I have seen attributes that have leading and/or trailing spaces and/or multiple consecutive space characters in the middle. Using normalize-space eliminates that problem.

Another thing is if QTP gives us multiple match error, we can use this trick to see if the xpath is working. Then keep working on to find the correct one.

(//div[contains(normalize-space(@class), 'xyz ng-binding ng-scope') and not(contains(@class, 'ng-hide'))])[1]
hxin
  • 938
  • 2
  • 12
  • 25
3

contains() is a function that takes two arguments: contains(A, B) returns true if B is a substring of A.

So your syntax would become valid if you replaced your "=" with ",": contains(@class, 'X') in place of contains(@class = 'X'). But I don't know whether it would then do what you want against all possible input data - that's a different question.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
0

you can use this expression for XPATH and contains:

//div[contains(@class, 'xyz ng-binding ng-scope')]

just use , instead of = in contains.

and when you want to combine it with not contain you can use this expression for not contains:not(expression) function. finally:

//div[contains(@class, 'xyz ng-binding ng-scope') and not(contains(@class , 'ng-hide'))]
behnam shateri
  • 1,223
  • 13
  • 18