So wählen Sie mit XPath das erste Element mit einem bestimmten Attribut aus

300

Der XPath bookstore/book[1]wählt den ersten Buchknoten unter aus bookstore.

Wie kann ich den ersten Knoten auswählen, der einer komplizierteren Bedingung entspricht, z. B. den ersten Knoten, der übereinstimmt? /bookstore/book[@location='US']

ripper234
quelle

Antworten:

444

Verwenden:

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

Dadurch werden zuerst die Buchelemente mit dem Standortattribut 'US' abgerufen. Dann wird der erste Knoten aus diesem Satz ausgewählt. Beachten Sie die Verwendung von Klammern, die für einige Implementierungen erforderlich sind.

Beachten Sie, dass dies nicht dasselbe ist, es /bookstore/book[1][@location='US']sei denn, das erste Element hat zufällig auch dieses Standortattribut.

Jonathan Fingland
quelle
Wie könnte ich dasselbe für // bookstore / book [@ location = 'US'] tun?
Alexander V. Ilyin
7
Dadurch erhalten Sie alle Bücher aus den USA. (/ bookstore / book [@ location = 'US']) [1] erhält den ersten.
Kevin Driedger
3
@KevinDriedger /bookstore/book[@location='US'][1]gibt nicht alle Bücher aus 'US' zurück. Ich habe es mehrmals und unter den xpath-Implementierungen verschiedener Sprachen getestet. /bookstore/book[@location='US'][1]gibt das erste "US" -Buch unter einem Buchladen zurück. Wenn es mehrere Buchhandlungen gibt, wird die erste von jeder zurückgegeben. Dies ist, was das OP angefordert hat (der erste Knoten unter dem Buchladen). Ihre Version gibt nur ein Buch aus allen Buchhandlungen zurück (das erste Spiel).
Jonathan Fingland
3
@ JonathanFingland, das Sie missverstanden haben - lesen Sie die Antwort von KevinDriedger noch einmal zusammen mit dem Kontext der Frage von AlexanderV.Ilyin. Sie meinen beide dasselbe.
Kiedysktos
175

/bookstore/book[@location='US'][1] funktioniert nur mit einfacher Struktur.

Fügen Sie etwas mehr Struktur hinzu und die Dinge brechen.

Mit

<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] ergibt

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

nicht "der erste Knoten, der einer komplizierteren Bedingung entspricht". /bookstore/category/book[@location='US'][2]gibt nichts zurück.

Mit Klammern können Sie das Ergebnis erhalten, für das die ursprüngliche Frage war:

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

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

und (/bookstore/category/book[@location='US'])[2]funktioniert wie erwartet.

tkurki
quelle
11
Autor der akzeptierten Antwort hier. Die Frage des OP wird berücksichtigt /bookstore/book[1]und NICHT (/bookstore/book)[1]. Der von Ihnen angegebene Fall ist nicht derselbe wie der, nach dem Sie gefragt haben. Vermutlich akzeptierte OP meine Antwort so, wie er es erwartet (und angefordert) hatte.
Jonathan Fingland
Diese Antwort half mir für diesen besonderen Fall. Kann jemand erklären, warum es nicht mit "komplizierteren Situationen" umgehen wird? Da es im Grunde eine Liste mit zwei Elementen findet, sollte die [2] sie einfach abholen (in meiner Welt)
Skurpi
Ich finde diese Antwort auch korrekter als die ausgewählte Antwort, da ich in meinem Fall auch eine komplexere Struktur hatte, bei der durch einfaches Hinzufügen von [1] mehrere Knoten zurückgegeben wurden. Vielen Dank!
Mydoghaswürmer
2
Klammern funktionieren! Sie können auch nach (..) [1] weitere Pfade hinzufügen, z '(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'. Falls viele Knoten übereinstimmen name.
Hlung
1
Ich ändere meine Meinung. Nach einiger Zeit verstehe ich, was diese Antwort sagte, und wenn ich das Beispiel des OP nicht gesehen hätte, hätte ich dafür gestimmt. Ich glaube, ich habe auf den Ton dieser Antwort reagiert; Wenn @tkurki etwas mehr über das Trennen der Bedingung von der Auswahl des ersten Knotens erklärt hätte, hätte ich es sofort gesehen. Vielleicht das gleiche für JonFingland.
Gerard ONeill
51

Als Erklärung zu Jonathan Finglands Antwort:

  • Mehrere Bedingungen im selben Prädikat ( [position()=1 and @location='US']) müssen als Ganzes wahr sein
  • mehrere Bedingungen in aufeinanderfolgenden Prädikate ( [position()=1][@location='US']) müssen wahr sein , eine nach der anderen
  • dies impliziert, dass [position()=1][@location='US']! = [@location='US'][position()=1]
    while [position()=1 and @location='US']==[@location='US' and position()=1]
  • Hinweis: Ein Einzelner [position()=1]kann abgekürzt werden[1]

Sie können komplexe Ausdrücke in Prädikaten mit den Booleschen Operatoren „bauen and“ und „ or“, und mit den Booleschen XPath - Funktionen not(), true()und false(). Außerdem können Sie Unterausdrücke in Klammern setzen.

Tomalak
quelle
15

Der einfachste Weg, den ersten englischen Buchknoten (im gesamten Dokument) zu finden, unter Berücksichtigung einer komplizierteren strukturierten XML-Datei wie:

<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> 

ist xpath Ausdruck:

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

Gee-Bee
quelle
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> 

Also angesichts der oben genannten; Sie können das erste Buch mit auswählen

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

Und dies wird der erste sein, der irgendwo einen Standort in den USA hat. [A1]

//book[@location='US']

Würde den Knoten zurückgeben, der mit allen Büchern mit dem Speicherort US festgelegt wurde. [A1, B1, C2]

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

Würde den ersten Buchspeicherort US zurückgeben, der in einer Kategorie irgendwo im Dokument vorhanden ist. [B1]

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

gibt das erste Buch mit dem Speicherort US zurück, das sich irgendwo unter dem Root-Element-Buchladen befindet; den / bookstore-Teil wirklich überflüssig machen. [A1]

In direkter Antwort:

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

Gibt Ihnen den ersten Knoten für das Buchelement mit dem Speicherort US zurück, der sich unter der Buchhandlung [A1] befindet.

Übrigens, wenn Sie wollten, finden Sie in diesem Beispiel das erste US-Buch, das kein direktes Kind der Buchhandlung war:

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

Verwenden Sie den Index, um den gewünschten Knoten zu erhalten, wenn xpath kompliziert ist oder mehr als ein Knoten mit demselben xpath vorhanden ist.

Ex :

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

Sie können die Nummer angeben, welchen Knoten Sie möchten.

Mounika Medipelli
quelle
2

Wenn für die angegebene XML-Datei ein Namespace bereitgestellt wird, ist es besser, diesen zu verwenden.

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

zum Beispiel.

<input b="demo">

Und

(input[@b='demo'])[1]
SenthilKumarP
quelle
-1

Mit Hilfe eines Online- Xpath-Testers schreibe ich diese Antwort ...
Dafür:

<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>

der folgende xpath:

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

Ausgänge:

123
foo
bar
xyz

Da 1 bedeutet, wählen Sie alle td- Elemente aus, die das erste Kind ihres eigenen direkten Elternteils sind.
Aber der folgende xpath:

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

Ausgänge:

123
Mohsen Abasi
quelle