2017-03-17 1 views
-1

J'utilise Rails 5 avec Nokogiri. Comment sélectionner le plus petit élément contenant du texte?Comment sélectionner le plus petit élément contenant du texte

Je cet élément sur ma page:

<td class="style35" style="font-size: medium; border: thin solid #000000"> 
         Location</td> 

et je pensais que je pouvais le sélectionner à l'aide:

doc.at('td:contains("Location")') 

Au lieu de cela, un td d'emballage qui contient la table qui contient cet élément est sélectionné :

<td><span class="myClass"><table> .... 

Quelle est la bonne façon d'écrire une expression qui sélectionne le smalle st (le plus petit?) élément qui contient le texte que je veux?

+2

Ce n'est pas « Nokogiri », il est « Nokogiri », « seleted » est « sélectionné », « teh » est « le », « ocntains » est "contient". La grammaire et l'orthographe sont importantes pour le SO. Votre question est le début d'une page de référence et les réponses sont les solutions au problème, comme une page dans une encyclopédie ou un livre de recettes. –

+1

Veuillez lire "[mcve]". Vous devez nous donner le plus petit exemple de HTML qui montrera le problème, d'une seule pièce, pas en morceaux séparés. Ne nous fais pas le reconstruire. –

Répondre

-1

Sélectionnez tous les éléments td, triez selon la longueur du contenu et choisissez le premier élément. Changez le sélecteur comme vous le souhaitez. Le tri est ascendant par défaut. Donc, vous obtenez les plus petits éléments en premier.

doc.css('td').sort_by do |td_element| 
    l.text.length 
end.first 
+0

Votre logique ne fonctionne pas pour mon cas, tho. L'expression "doc.at ('td: contains (" Location ")'" renvoie uniquement un seul élément Exécution de "doc.at ('td: contains (" Location ")').at ('td: contains ("Location")') "me donne l'élément que je veux pour ce cas particulier, mais en général je ne saurai pas combien de niveaux il faut forer pour trouver ce que je cherche – Dave

+0

Ce n'est pas une bonne logique Les cellules suivantes peuvent contenir des chaînes plus courtes que la valeur désirée De plus, votre exemple de code n'est pas valide Je vous recommande de tester votre code par rapport à l'exemple HTML et d'afficher vos résultats –

0

Si vous utilisez la méthode at, le premier résultat sera renvoyé.

La méthode css renvoie tous les éléments correspondant au sélecteur CSS, à la fois l'élément td correct et l'élément td entourant le tableau entier.

Si vous utilisez quelque chose comme ça, il trouvera tous les td balises, contenant le mot Location, il va stocker les éléments qui ne sont pas enveloppées autour d'une autre balise td dans un tableau:

td_with_no_child_and_have_location = [] 

doc.css("td:contains('Location')").each do |td_element| 
    if td_element.css("td").empty? 
     td_with_no_child_and_have_location << td_element 
    end 
end 

first_td = td_with_no_child_and_have_location.first 
+0

Je ne m'explique pas bien Je ne veux pas le TD avec le moins de HTML, je veux le TD qui n'a pas d'autre enfant TD et dont le texte contient le mot "Location" – Dave

+0

J'ai mis à jour ma réponse, de sorte qu'il stocke un tableau des éléments qui correspondent Vous pouvez utiliser le premier élément de ce tableau, si vous savez que votre élément sera toujours le premier –

+0

Merci pour cette mise à jour.Y a-t-il un moyen d'écrire un sélecteur CSS qui fait en une ligne ce que vous avez fait avec la boucle? – Dave

0

Il est difficile de vous aider si vous ne nous fournissez pas le HTML minimum. J'ai essayé de le recréer mais YMMV:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<html><body><table><tr> 
<td><span class="myClass"><table><tr> 
     <td class="style35" style="font-size: medium; border: thin solid #000000"> 
     Location</td> 
</tr></table></td></tr></table></html> 
EOT 
doc.at('.myClass td.style35').text # => "\n  Location" 

Si la balise que vous voulez est intégré dans une autre table, puis prendre avantage de quelques-unes des autres caractéristiques pour vous aider à naviguer, telles que les informations de classe. L'utilisation at devrait aider dans ce cas parce que typiquement le titre d'une table serait dans la première rangée qui contiendrait la première cellule. at est l'équivalent de search('some selector').first.

Le sélecteur ci-dessus pourrait même être écrit comme .myCLass .style35 ou td td qui trouverait le td dans un autre td. Combinez cela avec at et vous obtiendrez la première de ces étapes:

doc.at('.myClass td.style35').text # => "\n  Location" 
doc.at('.myClass .style35').text # => "\n  Location" 
doc.at('td td').text # => "\n  Location" 
+0

Je cherche un peu un peu plus général. Le TD n'aura pas toujours "myClass" en tant que classe. Je cherche le TD avec qui contient le texte donné sans autres TD à l'intérieur. – Dave

+0

Vous devez fournir plus d'informations dans votre question alors. Il est extrêmement large et ne répond pas aux directives de "[mcve]". Nous ne pouvons pas voter parce que vous avez une prime. Si vous essayez d'écrire une cellule générique "toujours trouver un titre" sans savoir à l'avance quel est le titre ou la structure du document, vous allez avoir du mal à le faire. –