Come selezionare il primo elemento con un attributo specifico usando XPath


300

XPath bookstore/book[1]seleziona il nodo del primo libro in bookstore.

Come posso selezionare il primo nodo che soddisfa una condizione più complicata, ad esempio il primo nodo che corrisponde /bookstore/book[@location='US']

Risposte:


444

Uso:

(/bookstore/book[@location='US'])[1]

Questo per prima cosa otterrà gli elementi del libro con l'attributo location uguale a "US". Quindi selezionerà il primo nodo da quel set. Nota l'uso delle parentesi, che sono richieste da alcune implementazioni.

Nota, questo non è lo stesso a /bookstore/book[1][@location='US']meno che il primo elemento non abbia anche quell'attributo location.


Come potrei fare lo stesso per // bookstore / book [@ location = 'US']?
Alexander V. Ilyin,

7
Questo otterrà tutti i libri dagli "Stati Uniti". (/ bookstore / book [@ location = 'US']) [1] otterrà il primo.
Kevin Driedger,

3
@KevinDriedger /bookstore/book[@location='US'][1]non restituisce tutti i libri da "US". L'ho testato più volte e con implementazioni xpath di lingue diverse. /bookstore/book[@location='US'][1]restituisce il primo libro "US" in una libreria. Se ci sono librerie multiple, allora restituirà il primo da ciascuna. Questo è ciò che l'OP ha richiesto (il primo nodo in libreria). La tua versione restituisce un solo libro di tutte le librerie (la prima partita).
Jonathan Fingland,

3
@JonathanFingland hai frainteso - leggi di nuovo la risposta di KevinDriedger, insieme al contesto della domanda di Alexander V. Ilyin. Intendete entrambi la stessa cosa.
kiedysktos,

175

/bookstore/book[@location='US'][1] funziona solo con una struttura semplice.

Aggiungi un po 'più di struttura e le cose si rompono.

Con

<bookstore>
 <category>
  <book location="US">A1</book>
  <book location="FIN">A2</book>
 </category>
 <category>
  <book location="FIN">B1</book>
  <book location="US">B2</book>
 </category>
</bookstore> 

/bookstore/category/book[@location='US'][1] i rendimenti

<book location="US">A1</book>
<book location="US">B2</book>

non "il primo nodo che corrisponde a una condizione più complicata". /bookstore/category/book[@location='US'][2]non restituisce nulla.

Con le parentesi puoi ottenere il risultato che la domanda originale era:

(/bookstore/category/book[@location='US'])[1]

<book location="US">A1</book>

e (/bookstore/category/book[@location='US'])[2]funziona come previsto.


11
Autore della risposta accettata qui. La domanda del PO è stata considerata /bookstore/book[1]e NON (/bookstore/book)[1]. Il caso che hai fornito non è lo stesso di quello richiesto. Presumibilmente, OP ha accettato la mia risposta in quanto ha fatto ciò che si aspettava (e richiesto).
Jonathan Fingland,

Questa risposta mi ha aiutato per questo caso particolare. Qualcuno può spiegare perché non gestirà "situazioni più complicate"? Dal momento che fondamentalmente trova un elenco con due elementi, il [2] dovrebbe semplicemente prenderlo (nel mio mondo)
Skurpi,

Trovo anche che questa risposta sia più corretta della risposta selezionata, poiché nel mio caso avevo anche una struttura più complessa in cui semplicemente l'aggiunta di [1] ha restituito più nodi. Grazie!
mydoghasworms,

2
Le parentesi funzionano! È inoltre possibile aggiungere ulteriori percorso dopo (..) [1], come: '(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'. Nel caso in cui ci siano molte corrispondenze di nodi name.
Hlung,

1
Sto cambiando la mia opinione. Dopo un po 'di distanza, capisco cosa stava dicendo questa risposta, e se non avessi visto l'esempio del PO avrei votato per questo. Suppongo che stavo reagendo al tono di questa risposta; se @tkurki avesse spiegato un po 'di più sulla separazione della condizione dalla selezione del primo nodo, l'avrei visto immediatamente. Forse lo stesso per JonFingland.
Gerard ONeill,

51

Come una spiegazione alla risposta di Jonathan Fingland:

  • più condizioni nello stesso predicato ( [position()=1 and @location='US']) devono essere vere nel loro insieme
  • più condizioni in predicati consecutivi ( [position()=1][@location='US']) devono essere vere una dopo l'altra
  • questo implica che [position()=1][@location='US']! = [@location='US'][position()=1]
    while [position()=1 and @location='US']==[@location='US' and position()=1]
  • suggerimento: un solitario [position()=1]può essere abbreviato in[1]

È possibile costruire espressioni complesse in predicati con gli operatori booleani " and" e " or", e con le funzioni booleane XPath not(), true()e false(). Inoltre puoi racchiudere le sottoespressioni tra parentesi.


15

Il modo più semplice per trovare il primo nodo di libri in inglese (nell'intero documento), prendendo in considerazione un file XML strutturato più complicato, come:

<bookstore>
 <category>
  <book location="US">A1</book>
  <book location="FIN">A2</book>
 </category>
 <category>
  <book location="FIN">B1</book>
  <book location="US">B2</book>
 </category>
</bookstore> 

è espressione xpath:

/descendant::book[@location='US'][1]


10
    <bookstore>
     <book location="US">A1</book>
     <category>
      <book location="US">B1</book>
      <book location="FIN">B2</book>
     </category>
     <section>
      <book location="FIN">C1</book>
      <book location="US">C2</book>
     </section>
    </bookstore> 

Quindi, dato quanto sopra; puoi selezionare il primo libro con

(//book[@location='US'])[1]

E questo troverà il primo ovunque che abbia una posizione negli Stati Uniti. [A1]

//book[@location='US']

Restituirebbe il set di nodi con tutti i libri con posizione negli Stati Uniti. [A1, B1, C2]

(//category/book[@location='US'])[1]

Restituirebbe la posizione del primo libro negli Stati Uniti che esiste in una categoria in qualsiasi parte del documento. [B1]

(/bookstore//book[@location='US'])[1]

restituirà il primo libro con la posizione negli Stati Uniti che esiste ovunque sotto la libreria dell'elemento radice; rendendo davvero ridondante la parte / libreria. [A1]

In risposta diretta:

/bookstore/book[@location='US'][1]

Ti restituirà il primo nodo per l'elemento libro con posizione US che è in libreria [A1]

Per inciso, se lo desideri, in questo esempio trovi il primo libro americano che non era un figlio diretto della libreria:

(/bookstore/*//book[@location='US'])[1]

4

Utilizzare l'indice per ottenere il nodo desiderato se xpath è complicato o più di un nodo è presente con lo stesso xpath.

Es:

(//bookstore[@location = 'US'])[index]

Puoi dare il numero quale nodo vuoi.


2

se lo spazio dei nomi è fornito sull'xml specificato, è meglio usarlo.

(/*[local-name() ='bookstore']/*[local-name()='book'][@location='US'])[1]


-1

Con l'aiuto di un tester xpath online sto scrivendo questa risposta ...
Per questo:

<table id="t2"><tbody>
<tr><td>123</td><td>other</td></tr>
<tr><td>foo</td><td>columns</td></tr>
<tr><td>bar</td><td>are</td></tr>
<tr><td>xyz</td><td>ignored</td></tr>
</tbody></table>

il seguente xpath:

id("t2") / tbody / tr / td[1]

uscite:

123
foo
bar
xyz

Poiché 1 significa selezionare tutti gli elementi td che sono il primo figlio del proprio genitore diretto.
Ma il seguente xpath:

(id("t2") / tbody / tr / td)[1]

uscite:

123
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.