Cách chọn phần tử đầu tiên với thuộc tính cụ thể bằng XPath


300

XPath bookstore/book[1]chọn nút sách đầu tiên bên dưới bookstore.

Làm cách nào tôi có thể chọn nút đầu tiên phù hợp với điều kiện phức tạp hơn, ví dụ: nút đầu tiên khớp với /bookstore/book[@location='US']

Câu trả lời:


444

Sử dụng:

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

Điều này trước tiên sẽ có được các thành phần sách có thuộc tính vị trí bằng 'US'. Sau đó, nó sẽ chọn nút đầu tiên từ tập hợp đó. Lưu ý việc sử dụng dấu ngoặc đơn, được yêu cầu bởi một số triển khai.

Lưu ý, điều này không giống như /bookstore/book[1][@location='US']trừ khi phần tử đầu tiên cũng có thuộc tính vị trí đó.


Làm cách nào tôi có thể làm tương tự cho // hiệu sách / sách [@ location = 'US']?
Alexander V. Ilyin

7
Điều này sẽ nhận được tất cả các cuốn sách từ 'US'. (/ hiệu sách / sách [@ location = 'US']) [1] sẽ nhận được cuốn đầu tiên.
Kevin Driger

3
@KevinDriedger /bookstore/book[@location='US'][1]không trả lại tất cả sách từ 'US'. Tôi đã thử nghiệm nó lần thứ hai và dưới các triển khai xpath của các ngôn ngữ khác nhau. /bookstore/book[@location='US'][1]trả lại cuốn sách 'US' đầu tiên dưới hiệu sách. Nếu có các cửa hàng sách đột biến, thì nó sẽ trả lại đầu tiên từ mỗi cửa hàng. Đây là những gì OP yêu cầu (nút đầu tiên trong hiệu sách). Phiên bản của bạn chỉ trả về một cuốn sách từ tất cả các nhà sách (trận đấu đầu tiên).
Jonathan Fingerland

3
@JonathanFingland bạn hiểu lầm - đọc lại câu trả lời của KevinDriedger, cùng với bối cảnh câu hỏi của AlexanderV.Ilyin. Cả hai bạn đều có cùng một ý nghĩa.
kiedysktos

175

/bookstore/book[@location='US'][1] chỉ hoạt động với cấu trúc đơn giản.

Thêm một chút cấu trúc và những thứ phá vỡ.

Với

<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] sản lượng

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

không phải "nút đầu tiên phù hợp với điều kiện phức tạp hơn". /bookstore/category/book[@location='US'][2]trả lại không có gì.

Với dấu ngoặc đơn, bạn có thể nhận được kết quả mà câu hỏi ban đầu dành cho:

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

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

(/bookstore/category/book[@location='US'])[2]hoạt động như mong đợi.


11
Tác giả của câu trả lời được chấp nhận ở đây. Câu hỏi của OP được xem xét /bookstore/book[1]và KHÔNG (/bookstore/book)[1]. Trường hợp bạn cung cấp không giống như trường hợp OP yêu cầu. Có lẽ, OP đã chấp nhận câu trả lời của tôi vì nó đã làm những gì anh ấy mong đợi (và yêu cầu).
Jonathan Fingerland

Câu trả lời này được cung cấp đã giúp tôi cho trường hợp đặc biệt này. Ai đó có thể giải thích lý do tại sao nó sẽ không xử lý "tình huống phức tạp hơn"? Vì về cơ bản, nó tìm thấy một danh sách có hai mục, [2] chỉ nên chọn nó (trong thế giới của tôi)
Skurpi

Tôi cũng thấy câu trả lời này đúng hơn câu trả lời đã chọn, vì trong trường hợp của tôi, tôi cũng có một cấu trúc phức tạp hơn khi chỉ cần thêm [1] trả lại nhiều nút. Cảm ơn!
mydoghasworms

2
Dấu ngoặc làm việc! Bạn cũng có thể thêm nhiều đường dẫn sau (..) [1], như : '(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'. Trong trường hợp có nhiều nút khớp name.
Hlung

1
Tôi đang thay đổi ý kiến ​​của mình. Sau một khoảng cách, tôi nhận được câu trả lời này là gì và nếu tôi không thấy ví dụ của OP, tôi sẽ bỏ phiếu cho điều này. Tôi cho rằng tôi đã phản ứng với giọng điệu của câu trả lời này; Nếu @tkurki đã giải thích thêm một chút về việc tách điều kiện khỏi lựa chọn nút đầu tiên, tôi sẽ thấy ngay lập tức. Có lẽ tương tự cho JonFingland.
Gerard ONeill

51

Như một lời giải thích cho câu trả lời của Jonathan Fingerland:

  • nhiều điều kiện trong ngữ tương tự ( [position()=1 and @location='US']) phải đúng như một toàn thể
  • nhiều điều kiện trong các vị từ liên tiếp ( [position()=1][@location='US']) phải đúng với nhau
  • điều này hàm ý rằng [position()=1][@location='US']! = [@location='US'][position()=1]
    while [position()=1 and @location='US']==[@location='US' and position()=1]
  • gợi ý: một mình [position()=1]có thể được viết tắt là[1]

Bạn có thể xây dựng biểu thức phức tạp trong các vị từ với các nhà khai thác Boolean " and" và " or", và với hàm Boolean XPath not(), true()false(). Ngoài ra, bạn có thể gói các biểu thức con trong ngoặc đơn.


15

Cách dễ nhất để tìm nút sách tiếng Anh đầu tiên (trong toàn bộ tài liệu), xem xét tệp xml phức tạp hơn, như:

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

là biểu thức 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> 

Vì vậy, đưa ra ở trên; bạn có thể chọn cuốn sách đầu tiên với

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

Và điều này sẽ tìm thấy cái đầu tiên ở bất cứ đâu có vị trí Mỹ. [A1]

//book[@location='US']

Sẽ trả về nút được đặt với tất cả các sách có vị trí US. [A1, B1, C2]

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

Sẽ trả lại vị trí sách đầu tiên Hoa Kỳ tồn tại trong một danh mục ở bất kỳ đâu trong tài liệu. [B1]

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

sẽ trả lại cuốn sách đầu tiên có vị trí Hoa Kỳ tồn tại ở bất cứ đâu dưới hiệu sách gốc của phần tử gốc; làm cho phần / hiệu sách thực sự dư thừa. [A1]

Trả lời trực tiếp:

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

Sẽ trả lại cho bạn nút đầu tiên cho thành phần sách có vị trí US nằm dưới hiệu sách [A1]

Ngẫu nhiên nếu bạn muốn, trong ví dụ này để tìm cuốn sách đầu tiên ở Hoa Kỳ không phải là con trực tiếp của hiệu sách:

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

4

Sử dụng chỉ mục để có được nút mong muốn nếu xpath phức tạp hoặc nhiều hơn một nút có cùng xpath.

Ví dụ :

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

Bạn có thể đưa ra số nút mà bạn muốn.


2

nếu không gian tên được cung cấp trên xml đã cho, tốt hơn là sử dụng nó.

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


-1

Với sự giúp đỡ của một người kiểm tra xpath trực tuyến Tôi đang viết câu trả lời này ...
Đối với điều này:

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

xpath sau:

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

đầu ra:

123
foo
bar
xyz

1 có nghĩa là chọn tất cả các phần tử td là con đầu tiên của cha mẹ trực tiếp của chúng.
Nhưng xpath sau:

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

đầu ra:

123
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.