web-dev-qa-db-fra.com

Comment puis-je faire correspondre un attribut contenant une certaine chaîne?

Je ne parviens pas à sélectionner les nœuds par attribut lorsque les attributs contiennent plus d'un mot. Par exemple:

<div class="atag btag" />

Ceci est mon expression xpath:

//*[@class='atag']

L'expression fonctionne avec

<div class="atag" />

mais pas pour l'exemple précédent. Comment puis-je sélectionner le <div>?

426
crazyrails

Cela les sélectionnera tous indépendamment de la position des attributs

//div[contains(@class, 'atag') and contains(@class ,'btag')]
467
surupa123

la réponse de mjv est un bon début, mais échouera si atag n'est pas le premier nom de classe indiqué.

L’approche habituelle est plutôt lourde:

//*[contains(concat(' ', @class, ' '), ' atag ')]

cela fonctionne tant que les classes ne sont séparées que par des espaces et non par d'autres formes d'espaces. C'est presque toujours le cas. Si ce n'est pas le cas, vous devez le rendre encore plus difficile à manier:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

(La sélection par des chaînes de caractères séparées par des espaces et ressemblant à un nom de classe est un cas si courant qu'il est surprenant de ne pas avoir de fonction XPath spécifique, comme le '[class ~ = "atag"] de CSS3.)

297
bobince

EDIT: voir la solution de bobince qui utilise contient plutôt que start-with , ainsi qu'une astuce pour s'assurer que la comparaison est faite au niveau d'un jeton complet (de peur que le motif 'atag' ne soit trouvé dans le cadre d'une autre 'balise').

"atag btag" est une valeur impaire pour l'attribut de classe, mais néanmoins, essayez:

//*[starts-with(@class,"atag")]
38
mjv

essayez ceci: //*[contains(@class, 'atag')]

33
SelenUser

Un XPath 2.0 qui fonctionne:

//*[tokenize(@class,'\s+')='atag']

ou avec une variable:

//*[tokenize(@class,'\s+')=$classname]
30
Daniel Haley

Sachez que la réponse de bobince pourrait être trop compliquée si vous pouvez supposer que le nom de la classe qui vous intéresse n’est pas une sous-chaîne d’un autre nom de classe possible. Si cela est vrai, vous pouvez simplement utiliser la correspondance de sous-chaîne via la fonction contient. Les éléments suivants correspondent à tout élément dont la classe contient la sous-chaîne 'atag':

//*[contains(@class,'atag')]

Si l'hypothèse ci-dessus ne tient pas, une correspondance de sous-chaîne correspondra à des éléments non souhaités. Dans ce cas, vous devez trouver les limites de Word. En utilisant les délimiteurs d'espace pour trouver les limites du nom de classe, la deuxième réponse de bobince trouve les correspondances exactes:

//*[contains(concat(' ', normalize-space(@class), ' '), ' atag ')]

Ceci correspondra à atag et non à matag.

20
Brent Atkinson

Pour ajouter à la réponse de bobince ... Si n'importe quel outil/bibliothèque que vous utilisez utilise Xpath 2.0, vous pouvez également le faire:

//*[count(index-of(tokenize(@class, '\s+' ), $classname)) = 1]

count () est apparemment nécessaire car index-of () renvoie une séquence de chaque index auquel elle correspond dans la chaîne.

7
armyofda12mnkeys

Vous pouvez essayer ce qui suit

By.CssSelector("div.atag.btag")

4
Umesh Chhabra

Pour les liens qui contiennent des URL communes doivent être consolé dans une variable. Puis essayez-le séquentiellement.

webelements allLinks=driver.findelements(By.xpath("//a[contains(@href,'http://122.11.38.214/dl/appdl/application/apk')]"));
int linkCount=allLinks.length();
for(int i=0; <linkCount;i++)
{
    driver.findelement(allLinks[i]).click();
}
0
user3906232