วิธีการเลือกองค์ประกอบแรกที่มีแอตทริบิวต์เฉพาะโดยใช้ XPath


300

XPath เลือกหนังสือเล่มแรกภายใต้โหนดbookstore/book[1]bookstore

ฉันจะเลือกโหนดแรกที่ตรงกับเงื่อนไขที่ซับซ้อนมากขึ้นได้อย่างไรเช่นโหนดแรกที่ตรงกับ /bookstore/book[@location='US']

คำตอบ:


444

ใช้:

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

สิ่งนี้จะได้รับองค์ประกอบหนังสือที่มีแอตทริบิวต์ตำแหน่งเท่ากับ 'US' จากนั้นมันจะเลือกโหนดแรกจากชุดนั้น หมายเหตุการใช้วงเล็บซึ่งจำเป็นต้องมีการใช้งานบางอย่าง

หมายเหตุสิ่งนี้ไม่เหมือนกัน/bookstore/book[1][@location='US']เว้นแต่ว่าองค์ประกอบแรกจะมีแอตทริบิวต์ตำแหน่งนั้นด้วย


ฉันจะทำแบบเดียวกันกับ // bookstore / book [@ location = 'US'] ได้อย่างไร
Alexander V. Ilyin

7
นี่จะได้รับหนังสือทั้งหมดจาก 'US' (/ bookstore / book [@ location = 'US']) [1] จะได้รับรางวัลแรก
Kevin Driedger

3
@KevinDriedger /bookstore/book[@location='US'][1]ไม่ส่งคืนหนังสือทั้งหมดจาก 'US' ฉันได้ทดสอบมันหลายครั้งและภายใต้การใช้งาน xpath ของภาษาต่างๆ /bookstore/book[@location='US'][1]ส่งคืนหนังสือ 'US' เล่มแรกภายใต้ร้านหนังสือ หากมีร้านหนังสือหลายร้านก็จะกลับมาที่ร้านแรก นี่คือสิ่งที่ OP ขอ (โหนดแรกภายใต้ร้านหนังสือ) เวอร์ชันของคุณจะส่งคืนหนังสือเพียงเล่มเดียวจากร้านหนังสือทั้งหมด (คู่แรก)
Jonathan Fingland

3
@ JonathanFingland คุณเข้าใจผิด - อ่านคำตอบของ KevinDriedger อีกครั้งพร้อมกับบริบทของคำถาม AlexanderV.Ilyin คุณทั้งคู่หมายถึงสิ่งเดียวกัน
kiedysktos

175

/bookstore/book[@location='US'][1] ทำงานได้เฉพาะกับโครงสร้างที่เรียบง่าย

เพิ่มโครงสร้างและสิ่งต่าง ๆ อีกเล็กน้อย

กับ

<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] อัตราผลตอบแทน

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

ไม่ใช่ "โหนดแรกที่ตรงกับเงื่อนไขที่ซับซ้อนกว่า" /bookstore/category/book[@location='US'][2]ไม่มีอะไรคืน

ด้วยวงเล็บคุณจะได้รับผลลัพธ์คำถามเดิมมีไว้สำหรับ:

(/bookstore/category/book[@location='US'])[1] จะช่วยให้

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

และ(/bookstore/category/book[@location='US'])[2]ทำงานตามที่คาดไว้


11
ผู้เขียนคำตอบที่ยอมรับได้ที่นี่ คำถาม OP 's ได้รับการยกย่อง/bookstore/book[1]และ (/bookstore/book)[1]NOT กรณีที่คุณระบุไม่ตรงกับที่ OP ขอ สันนิษฐานว่า OP ยอมรับคำตอบของฉันตามที่เขาคาดหวังไว้ (และขอ)
Jonathan Fingland

คำตอบนี้ให้ช่วยฉันสำหรับกรณีที่แปลกประหลาดนี้ ใครสามารถอธิบายได้ว่าทำไมมันถึงไม่จัดการกับ เนื่องจากโดยพื้นฐานแล้วมันจะค้นหารายการที่มีสองรายการดังนั้น [2] จึงควรหยิบมันขึ้นมา (ในโลกของฉัน)
Skurpi

ฉันพบว่าคำตอบนี้ถูกต้องมากกว่าคำตอบที่เลือกเช่นในกรณีของฉันฉันยังมีโครงสร้างที่ซับซ้อนมากขึ้นโดยเพียงเพิ่ม [1] คืนหลายโหนด ขอบคุณ!
mydoghasworms

2
วงเล็บใช้งานได้! นอกจากนี้คุณยังสามารถเพิ่มมากขึ้นหลังจากที่เส้นทาง ( .. ) [1], '(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'เช่น: nameในกรณีที่มีโหนดจำนวนตรงกับที่
Hlung

1
ฉันเปลี่ยนความคิดเห็นของฉัน หลังจากระยะไกลฉันก็ได้คำตอบที่ว่านี้และถ้าฉันไม่เห็นตัวอย่างของ OP ฉันจะโหวตให้กับสิ่งนี้ ฉันคิดว่าฉันตอบสนองต่อน้ำเสียงของคำตอบนี้; ถ้า @tkurki ได้อธิบายเพิ่มเติมเล็กน้อยเกี่ยวกับการแยกเงื่อนไขออกจากการเลือกโหนดแรกฉันจะเห็นทันที อาจเหมือนกันสำหรับ JonFingland
เจอราร์ดโอนีล

51

ตามคำอธิบายของโจนาธานฟิงแลนด์คำตอบ:

  • เงื่อนไขหลายข้อในภาคแสดงเดียวกัน ( [position()=1 and @location='US']) จะต้องเป็นจริงโดยรวม
  • หลายเงื่อนไขในเพรดิเคตที่ต่อเนื่องกัน ( [position()=1][@location='US']) จะต้องเป็นจริงหลังจากนั้นอีกหนึ่งเงื่อนไข
  • นี่หมายความว่า[position()=1][@location='US']! = [@location='US'][position()=1]
    ในขณะที่[position()=1 and @location='US']==[@location='US' and position()=1]
  • คำใบ้: หนึ่งเดียว[position()=1]สามารถยากที่จะ[1]

คุณสามารถสร้างการแสดงออกที่ซับซ้อนในภาคที่มีผู้ประกอบการบูลีน " and" และ " or" และมีฟังก์ชั่นแบบบูล XPath not(), และtrue() false()ยิ่งไปกว่านั้นคุณสามารถห่อนิพจน์ย่อยในวงเล็บ


15

วิธีที่ง่ายที่สุดในการค้นหาโหนดหนังสือภาษาอังกฤษแรก (ในเอกสารทั้งหมด) โดยพิจารณาไฟล์ xml ที่มีโครงสร้างที่ซับซ้อนกว่าเช่น:

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

คือนิพจน์ 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> 

ดังนั้นที่ได้รับข้างต้น; คุณสามารถเลือกหนังสือเล่มแรกด้วย

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

และนี่จะหาอันแรกที่ใดก็ได้ที่มีที่ตั้งของสหรัฐฯ [A1]

//book[@location='US']

จะส่งคืนโหนดที่ตั้งค่าด้วยหนังสือทั้งหมดที่มีตำแหน่ง US [A1, B1, C2]

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

จะส่งคืนตำแหน่งหนังสือเล่มแรกของสหรัฐอเมริกาที่มีอยู่ในหมวดหมู่ใดก็ได้ในเอกสาร [B1]

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

จะส่งคืนหนังสือเล่มแรกที่มีสถานที่ตั้งของสหรัฐอเมริกาซึ่งอยู่ที่ใดก็ได้ภายใต้ร้านหนังสือองค์ประกอบรูต ทำให้ส่วน / ร้านหนังสือซ้ำซ้อนจริงๆ [A1]

ตอบโดยตรง:

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

จะส่งคืนโหนดแรกให้คุณสำหรับองค์ประกอบหนังสือที่มีสถานที่ตั้งของสหรัฐอเมริกาซึ่งอยู่ภายใต้ร้านหนังสือ [A1]

บังเอิญถ้าคุณต้องการในตัวอย่างนี้เพื่อค้นหาหนังสือเล่มแรกของสหรัฐอเมริกาที่ไม่ใช่ลูกของร้านหนังสือโดยตรง:

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

4

ใช้ดัชนีเพื่อรับโหนดที่ต้องการถ้า xpath ซับซ้อนหรือมีมากกว่าหนึ่งโหนดที่มี xpath เดียวกัน

เช่น

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

คุณสามารถระบุหมายเลขที่คุณต้องการโหนด




-1

ด้วยความช่วยเหลือของผู้ทดสอบ xpathออนไลน์ฉันกำลังเขียนคำตอบนี้ ...
สำหรับสิ่งนี้:

<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 ต่อไปนี้:

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

เอาท์พุท:

123
foo
bar
xyz

ตั้งแต่1หมายถึงเลือกองค์ประกอบtdทั้งหมดซึ่งเป็นลูกคนแรกของผู้ปกครองโดยตรงของตัวเอง
แต่ xpath ต่อไปนี้:

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

เอาท์พุท:

123
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.