Utilisation de XPATH pour rechercher du texte contenant & nbsp;


120

J'utilise XPather navigateur pour vérifier mes expressions XPATH sur une page HTML.

Mon objectif final est d'utiliser ces expressions dans Selenium pour tester mes interfaces utilisateur.

J'ai un fichier HTML avec un contenu similaire à celui-ci:

<tr>
  <td> abc </td>
  <td> & nbsp; </td>
</tr>

Je souhaite sélectionner un nœud avec un texte contenant la chaîne " &nbsp;".

Avec une chaîne normale comme "abc", il n'y a pas de problème. J'utilise un XPATH similaire à //td[text()="abc"].

Quand j'essaye avec un XPATH comme //td[text()="&nbsp;"]ça ne renvoie rien. Existe-t-il une règle spéciale concernant les textes avec " &"?


Votre transformation XSL réelle ne renvoie-t-elle rien? Ou seulement Xpather?
Zack The Human

Réponses:


89

Il semble qu'OpenQA , les gars derrière Selenium, ont déjà résolu ce problème. Ils ont défini certaines variables pour correspondre explicitement aux espaces. Dans mon cas, je dois utiliser un XPATH similaire à //td[text()="${nbsp}"].

J'ai reproduit ici le texte d'OpenQA concernant ce problème (trouvé ici ):

HTML normalise automatiquement les espaces dans les éléments, ignorant les espaces de début / de fin et convertissant les espaces supplémentaires, les tabulations et les retours à la ligne en un seul espace. Lorsque Selenium lit le texte de la page, il tente de dupliquer ce comportement, vous pouvez donc ignorer tous les onglets et nouvelles lignes de votre HTML et faire des assertions en fonction de l'apparence du texte dans le navigateur une fois rendu. Nous faisons cela en remplaçant tous les espaces non visibles (y compris l'espace insécable " &nbsp;") par un seul espace. Toutes les nouvelles lignes visibles ( <br>, <p>et les <pre>nouvelles lignes formatées) doivent être conservées.

Nous utilisons la même logique de normalisation sur le texte des tableaux de cas de test HTML Selenese. Cela présente de nombreux avantages. Tout d'abord, vous n'avez pas besoin de regarder la source HTML de la page pour déterminer quelles devraient être vos affirmations; Les &nbsp;symboles " " sont invisibles pour l'utilisateur final, et vous ne devriez donc pas avoir à vous en soucier lors de l'écriture des tests Selenese. (Vous n'avez pas besoin de mettre des &nbsp;marqueurs " " dans votre scénario de test pour assertText sur un champ qui contient " &nbsp;".) Vous pouvez également mettre des nouvelles lignes et des espaces supplémentaires dans vos <td>balises Selenese ; puisque nous utilisons la même logique de normalisation sur le cas de test que sur le texte, nous pouvons nous assurer que les assertions et le texte extrait correspondent exactement.

Cela crée un petit problème dans les rares occasions où vous voulez / avez vraiment besoin d'insérer des espaces supplémentaires dans votre scénario de test. Par exemple, vous devrez peut-être saisir du texte dans un champ comme celui-ci: " foo ". Mais si vous écrivez simplement <td>foo </td>dans votre cas de test Selenese, nous remplacerons vos espaces supplémentaires par un seul espace.

Ce problème a une solution de contournement simple. Nous avons défini une variable en Selenese ${space}, dont la valeur est un seul espace. Vous pouvez utiliser ${space}pour insérer un espace qui ne sera pas automatiquement coupé, comme ceci: <td>foo${space}${space}${space}</td>. Nous avons également inclus une variable ${nbsp}, que vous pouvez utiliser pour insérer un espace insécable.

Notez que XPaths ne normalise pas les espaces comme nous le faisons. Si vous avez besoin d'écrire un XPath comme //div[text()="hello world"]mais le code HTML du lien est vraiment « hello&nbsp;world», vous aurez besoin d'insérer un véritable « &nbsp;» dans votre cas de test Selenese pour l' obtenir pour correspondre, comme ceci: //div[text()="hello${nbsp}world"].


1
Le lien OpenQA ne se charge plus avec succès
kjosh

1
Je veux juste noter que $ {nbsp} ne fonctionne pas pour moi dans les outils de développement Selenium ou Chrome, pas plus \u00a0. Ce qui a fonctionné pour moi a été de taper un espace insécable, sur mac Alt+Shift+Space. La recherche Web dit Alt+0160sur Windows.
Cynic

25

J'ai trouvé que je pouvais faire la correspondance lorsque j'entrais un espace insécable codé en dur (U + 00A0) en tapant Alt + 0160 sous Windows entre les deux guillemets ...

//table[@id='TableID']//td[text()=' ']

travaillé pour moi avec le personnage spécial.

D'après ce que j'ai compris, le standard XPath 1.0 ne gère pas les caractères Unicode qui s'échappent. Il semble y avoir des fonctions pour cela dans XPath 2.0 mais il semble que Firefox ne le supporte pas (ou j'ai mal compris quelque chose). Vous avez donc à voir avec la page de codes locale. Moche, je sais.

En fait, il semble que la norme s'appuie sur le langage de programmation utilisant XPath pour fournir la séquence d'échappement Unicode correcte ... Donc, d'une manière ou d'une autre, j'ai fait la bonne chose.


En utilisant Xpather 1.4.1 dans Firefox 2, // td [text () = ''] ne donne aucun résultat.
Zack The Human

Désolé. Ça ne marche pas pour moi. Mon objectif final est de l'utiliser dans Selenium pour les tests de mes interfaces Web. Selenium lui-même conserve les expressions de test dans une structure XML et le typage Alt Windows semble être perdu. Aussi, mon & # 160; renvoie comme un dans XML.
Bergeroy

Zack, comme je l'ai écrit, vous devez remplacer l'espace entre les deux guillemets par le caractère produit par Alt + 0160 (sur le pavé numérique).
PhiLho

4
$col = $xpath->query("//p[text()=\"\xC2\xA0\"]");
Je dois également

@Bergory Cela fonctionne en utilisant Protractor avec pilote Selenium
Damian Green

4

Essayez d'utiliser l'entité décimale au &#160;lieu de l'entité nommée. Si cela ne fonctionne pas, vous devriez pouvoir utiliser simplement le caractère Unicode pour un espace insécable au lieu de l' &nbsp;entité.

(Remarque: je n'ai pas essayé ceci dans XPather, mais je l'ai essayé dans Oxygen.)


2

Gardez à l' esprit qu'un processeur XML conforme aux normes aura remplacé toutes les références d'entités autres que les standards de cinq XML ( &amp;, &gt;, &lt;, &apos;, &quot;) avec le caractère correspondant dans le codage cible au moment où les expressions XPath sont évaluées. Compte tenu de ce comportement, les suggestions de PhiLho et de jsulak sont la voie à suivre si vous souhaitez travailler avec des outils XML. Lorsque vous entrez &#160;dans l'expression XPath, elle doit être convertie dans la séquence d'octets correspondante avant que l'expression XPath ne soit appliquée.


1
Pas si vous essayez / utilisez XPath dans XPather (GUI) ou en JavaScript (pas d'auto-substitution d'entités, puisque nous ne sommes pas en XML). Bons conseils dans d'autres environnements XML (XSTL?).
PhiLho

1

Je ne peux pas obtenir de correspondance avec Xpather, mais ce qui suit a fonctionné pour moi avec des fichiers XML et XSL simples dans le bloc-notes XML de Microsoft:

<xsl:value-of select="count(//td[text()='&nbsp;'])" />

La valeur renvoyée est 1, qui est la valeur correcte dans mon scénario de test.

Cependant, j'ai dû déclarer nbsp en tant qu'entité dans mon XML et XSL en utilisant ce qui suit:

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>

Je ne sais pas si cela vous aide, mais j'ai pu réellement trouver nbsp en utilisant une expression XPath.

Modifier: mon exemple de code contient en fait les caractères «& nbsp;» mais la surbrillance de la syntaxe JavaScript le convertit en caractère d'espace. Ne soyez pas induit en erreur!


Vous pouvez modifier votre exemple de code comme cela a été fait pour l'exemple dans ma question. Remplacez votre entité nbsp par & amp; nbsp ;.
Bergeroy

1

Rechercher &nbsp;ou seulement nbsp- avez-vous essayé cela?


Je reconnais que cela devrait fonctionner, mais je ne sais pas exactement ce que je trouve. Il doit y avoir un moyen dans XPATH pour encoder une certaine manière de correspondre à ce que je recherche.
Bergeroy

Je devrais peut-être regarder vers une expression régulière.
Bergeroy

1

Selon le HTML que vous avez fourni:

<tr>
  <td>abc</td>
  <td>&nbsp;</td>
</tr>

Pour localiser le nœud avec la chaîne, &nbsp;vous pouvez utiliser l'une des méthodes suivantes solutions basées sur:

  • Utilisation text():

    "//td[text()='\u00A0']"
  • Utilisation contains():

    "//td[contains(., '\u00A0')]"

Cependant, dans l'idéal, vous pouvez éviter le caractère NO-BREAK SPACE et utiliser l'une des stratégies de localisation suivantes :

  • En utilisant le <tr>nœud parent et following-sibling:

    "//tr//following-sibling::td[2]"
  • Utilisation starts-with():

    "//tr//td[last()]"
  • Utilisation du <td>nœud précédent et followingnode anddu frère suivant`:

    "//td[text()='abc']//following::td[1]"

Référence

Vous pouvez trouver une discussion détaillée pertinente dans:


tl; dr

Caractère Unicode 'NO-BREAK SPACE' (U + 00A0)


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.