2010-10-24 4 views
83

Il existe un fichier HTML (dont je ne contrôle pas le contenu) qui a plusieurs éléments input tous avec le même attribut id fixe de "search_query". Le contenu du fichier peut changer, mais je sais que je veux toujours obtenir le deuxième élément input avec l'attribut id "search_query".Requête XPath pour obtenir la nième instance d'un élément

J'ai besoin d'une expression XPath pour cela. J'ai essayé //input[@id="search_query"][2] mais cela ne fonctionne pas. Voici une chaîne XML exemple où cette requête a échoué:

<div> 
    <form> 
    <input id="search_query" /> 
    </form> 
</div> 

<div> 
    <form> 
    <input id="search_query" /> 
    </form> 
</div> 

<div> 
    <form> 
    <input id="search_query" /> 
    </form> 
</div> 

Gardez à l'esprit que ce qui précède est simplement un exemple et l'autre code HTML peut être tout à fait différent et les input éléments peuvent apparaître n'importe où sans structure du document uniforme (sauf que je suis garanti qu'il y aura toujours au moins deux éléments input avec un attribut id de "search_query").

Quelle est l'expression XPath correcte?

+0

Bonne question, +1. Voir ma réponse pour une explication complète du problème et pour la solution recherchée. –

+2

Point secondaire: vous ne devriez jamais avoir plus d'un élément avec un ID donné (et ainsi le HTML dans la question est réellement invalide). En pratique, les navigateurs vous permettent de le faire de toute façon, mais si vous le faites, vous ne profitez pas du seul avantage de l'utilisation des ID, à savoir qu'ils signalent «Je suis unique» (alors que les classes sont conçues pour être utilisées signifiants uniques). – machineghost

Répondre

149

C'est une FAQ:

//somexpression[$N]

signifie "Trouver chaque noeud sélectionné par //somexpression qui est l'enfant $N e de sa mère".

Qu'est-ce que vous voulez est:

(//input[@id="search_query"])[2] 

Rappelez-vous: L'opérateur a [] que l'abréviation // une priorité plus élevée (priorité).

+3

J'aime cette réponse. Je n'avais pas considéré un problème de précédence (j'ai simplement supposé une préséance simple de gauche à droite). – rlandster

+6

@rlandster: Le mot "precedence" peut prêter à confusion. La forme non abrégée de '// input [@ id = 'search_query'] [2]' est: '/ descendat-or-self :: node()/enfant :: entrée [attribut :: id = 'search_query'] [ position() = 2] ' –

9

Cela semble fonctionner:

/descendant::input[@id="search_query"][2] 

Je vais de ce "XSLT 2.0 et XPath 2.0 Référence de programmeur, 4e édition" par Michael Kay.

Il existe également une note dans la section "Syntaxe abrégée" de la spécification XML Path Language http://www.w3.org/TR/xpath/#path-abbrev qui fournit un indice.

+0

Un grand merci pour cette réponse. Dans mon cas, la solution acceptée ne fonctionnerait pas car j'utilise le xpath dans le cadre du robot, qui n'accepterait pas les chemins commençant par des crochets. Celui-ci cependant, devrait faire l'affaire – dahui

Questions connexes