วิธีใช้ XPath มี () ที่นี่?


142

ฉันพยายามเรียนรู้ XPath ฉันดูcontains()ตัวอย่างอื่นๆ แถวนี้ แต่ไม่มีอะไรที่ใช้ตัวดำเนินการAND ฉันไม่สามารถทำงานนี้ได้:

//ul[@class='featureList' and contains(li, 'Model')]

บน:

...
<ul class="featureList">

<li><b>Type:</b> Clip Fan</li><li><b>Feature:</b> Air Moved: 65 ft.
    Amps: 1.1
    Clip: Grips any surface up to 1.63"
    Plug: 3 prong grounded plug on heavy duty model
    Usage: Garage, Workshop, Dorm, Work-out room, Deck, Office & more.</li><li><b>Speed Setting:</b> 2 speeds</li><li><b>Color:</b> Black</li><li><b>Power Consumption:</b> 62 W</li><li><b>Height:</b> 14.5"</li><li><b>Width:</b> Grill Diameter: 9.5"</li><li><b>Length:</b> 11.5"</li>

<li><b>Model #: </b>CR1-0081-06</li>
<li><b>Item #: </b>N82E16896817007</li>
<li><b>Return Policy: </b></li>
</ul>
...

สิ่งนี้ใช้ได้กับฉันฉันทดสอบในwhitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm
mihi

คำตอบ:


199

คุณดูที่liเด็กคนแรกในแบบสอบถามที่คุณมีแทนที่จะมองหาliองค์ประกอบลูกที่อาจมีข้อความ'Model'อยู่ สิ่งที่คุณต้องการคือแบบสอบถามดังต่อไปนี้:

//ul[@class='featureList' and ./li[contains(.,'Model')]]

แบบสอบถามนี้จะทำให้คุณมีองค์ประกอบที่มีclassของfeatureListหนึ่งคนหรือมากกว่าเด็กที่มีข้อความli'Model'


13
+1 - "./" เป็นการเข้าใจผิดเล็กน้อย - มันแสดงให้เห็นว่าสิ่งอื่นใดนอกจากโหนดปัจจุบันจะถูกนำมาพิจารณาเมื่อคุณปล่อยมันออกมา แต่ในความเป็นจริงมันซ้ำซ้อน: "// ul [@ class = ' featureList 'และ li [ประกอบด้วย (.,' Model ')]] "" เป็นสิ่งเดียวกัน
Tomalak

4
ใช่ฉันเป็นคนเฉพาะเจาะจง ค่อนข้างเฉพาะเจาะจงมากเกินไป
Jeff Yates

ถ้าไม่มีliมีModelในulแล้วandสภาพจะล้มเหลว ดังนั้นandเงื่อนไขส่งกลับfalseในชุดว่างเปล่าถูกต้องหรือไม่
damluar

58

ฉันมอบโซลูชัน +1 ให้กับ Jeff Yates แล้ว

นี่คือคำอธิบายอย่างรวดเร็วว่าทำไมวิธีการของคุณไม่ทำงาน นี้:

// ul [@ class = 'featureList' และมี (li, 'Model')]

พบข้อ จำกัด ของcontains()ฟังก์ชัน (หรือฟังก์ชันสตริงอื่น ๆ ใน XPath สำหรับเรื่องนั้น)

อาร์กิวเมนต์แรกควรเป็นสตริง ถ้าคุณป้อนรายการโหนด (การให้มันliทำอย่างนั้น) จะต้องมีการแปลงเป็นสตริง แต่การแปลงนี้ทำสำหรับโหนดแรกในรายการเท่านั้น

ในกรณีของคุณโหนดแรกในรายการคือ<li><b>Type:</b> Clip Fan</li>(แปลงเป็นสตริง: " Type: Clip Fan") ซึ่งหมายความว่า:

// ul [@ class = 'featureList' และมี (li, 'Type')]

จะเลือกโหนดจริงๆ!


1
เป็นคนดีพยายามดิ้นรนเพื่อค้นหาว่าเหตุใดข้อความค้นหาเช่น: ".//tdiplecontains(.//*,'something ')]" ทำงานได้แค่ระดับความลึก 1 ฉันจะหาวิธีทำงานได้ แต่ก็ไม่ได้ แน่ใจว่าวิธีการข้างต้นทำงานได้ทั้งหมด สิ่งที่ฉันต้องการจริง ๆ คือ ".//tdه.//* containstainstainstains(tainstainstainstains'somomomomomom '' '
JonnyRaa

11

นี่คือคำตอบใหม่ไปยังคำถามเดิมเกี่ยวกับความเข้าใจผิดกันเกี่ยวกับcontains()ใน XPath ...

สรุป: contains()หมายถึงมีสตริงย่อย , ไม่ได้ มีโหนด

คำอธิบายโดยละเอียด

XPath นี้มักตีความผิด:

//ul[contains(li, 'Model')]

การตีความผิด: เลือกเหล่านั้นulองค์ประกอบที่มีliองค์ประกอบที่มีModelอยู่ในนั้น

นี่เป็นสิ่งที่ผิดเพราะ

  1. contains(x,y)คาดว่าxจะเป็นสตริงและ
  2. กฎ XPath การแปลงหลายองค์ประกอบสตริงเป็นนี้ :

    โหนดชุดจะถูกแปลงเป็นสตริงโดยกลับสตริงค่าของโหนดในโหนชุดที่เป็นครั้งแรกในการสั่งซื้อเอกสาร หากชุดโหนดว่างเปล่าสตริงว่างจะถูกส่งกลับ

การตีความขวา:เลือกผู้ulองค์ประกอบซึ่งเป็นครั้งแรก liที่เด็กมีสตริงที่มีมูลค่าที่มีModelย่อย

ตัวอย่าง

XML

<r>
  <ul id="one">
    <li>Model A</li>
    <li>Foo</li>
  </ul>
  <ul id="two">
    <li>Foo</li>
    <li>Model A</li>
  </ul>
</r> 

XPaths

  • //ul[contains(li, 'Model')]เลือกone ulองค์ประกอบ

    หมายเหตุ:two ulองค์ประกอบไม่ได้เลือกเพราะสตริงค่าแรกliลูกของtwo ulเป็นFooซึ่งไม่ได้มีModelย่อย

  • //ul[li[contains(.,'Model')]]เลือกoneและtwo ulองค์ประกอบ

    หมายเหตุ:ทั้งสองulองค์ประกอบที่จะถูกเลือกเพราะcontains()ถูกนำไปใช้แต่ละliรายบุคคล (ดังนั้นกฎการแปลงหลายองค์ประกอบเป็นสตริงหากินถูกหลีกเลี่ยง) ulองค์ประกอบทั้งสองมีliเด็กที่ค่าสตริงมีModelสตริงย่อย - ตำแหน่งของliองค์ประกอบไม่สำคัญอีกต่อไป

ดูสิ่งนี้ด้วย



-5

วางcontainsตัวอย่างของฉันที่นี่:

//table[contains(@class, "EC_result")]/tbody

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