การเลือกคลาส css ด้วย xpath


87

ฉันต้องการเลือกเพียงชั้นเรียนในตัวเองที่เรียกว่า. วันที่

ด้วยเหตุผลบางประการฉันไม่สามารถทำงานนี้ได้ หากใครรู้ว่ารหัสของฉันผิดพลาดจะได้รับการชื่นชมมาก

@$doc = new DOMDocument();
@$doc->loadHTML($html);
$xml = simplexml_import_dom($doc); // just to make xpath more simple
$images = $xml->xpath('//[@class="date"]');                             
foreach ($images as $img)
{
    echo  $img." ";
}

2
แล้วส่วนของ html ล่ะ? (โปรดแสดงเอาต์พุต simpleXml จาก asXML () ให้เราดูเนื่องจากใกล้ xpath มากขึ้น)
SergeS

หากมีหลายชั้นเรียนคุณต้องทำcontains(@class, 'date')
Gordon



คำตอบของ @ Gordon นั้นอันตรายถ้าแอตทริบิวต์คลาสคือ "วันที่และเวลา" ก็จะตรงกันเช่นกัน คำตอบของ user716736 นั้นสมบูรณ์ยิ่งขึ้น
Niels Bom

คำตอบ:


242

ฉันต้องการเขียนคำตอบที่เป็นมาตรฐานสำหรับคำถามนี้เนื่องจากคำตอบด้านบนมีปัญหา

ปัญหาของเรา

CSSเลือก:

.foo

จะเลือกองค์ประกอบใด ๆ ที่มีชั้นfoo

คุณทำสิ่งนี้ใน XPath ได้อย่างไร?

แม้ว่า XPath จะมีประสิทธิภาพมากกว่า CSS แต่XPath ไม่มีตัวเลือกคลาส CSS ที่เทียบเท่ากับเนทีฟ อย่างไรก็ตามมีวิธีแก้ไข

วิธีทำที่ถูกต้อง

ตัวเลือกที่เทียบเท่าในXPathคือ:

//*[contains(concat(" ", normalize-space(@class), " "), " foo ")]

ฟังก์ชันnormalize-spaceแถบช่องว่างที่นำหน้าและต่อท้าย (และยังแทนที่ลำดับของอักขระช่องว่างด้วยช่องว่างเดียว)

(ในความหมายทั่วไป) นี่ก็เทียบเท่ากับตัวเลือก CSS:

*[class~="foo"]

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

สองวิธีที่ชัดเจน แต่ไม่ถูกต้องในการทำ

ตัวเลือก XPath:

//*[@class="foo"]

ใช้ไม่ได้! เนื่องจากจะไม่ตรงกับองค์ประกอบที่มีมากกว่าหนึ่งคลาสเป็นต้น

<div class="foo bar">

นอกจากนี้จะไม่ตรงกันหากมีช่องว่างเพิ่มเติมรอบชื่อคลาส:

<div class="  foo ">

ตัวเลือก XPath ที่ 'ปรับปรุงแล้ว

//*[contains(@class, "foo")]

ใช้ไม่ได้เหมือนกัน! เนื่องจากจับคู่องค์ประกอบกับคลาสfoobarอย่างไม่ถูกต้องเช่น

<div class="foobar">

เครดิตไปที่เพื่อนคนนี้ซึ่งเป็นวิธีการแก้ปัญหาที่เผยแพร่เร็วที่สุดสำหรับปัญหานี้ที่ฉันพบบนเว็บ: http://dubinko.info/blog/2007/10/01/simple-parsing-of-space-seprated-attributes- ใน xpathxslt /


อะไรคือความจำเป็นในการ normalize-space?
ฟรี

"คำตอบข้างต้น" อาจหมายถึงของ MrGlass
LarsH

เป็นไปได้<div class="foo\tbar">หรือไม่ ฉันหมายถึงชื่อคลาสคั่นด้วยแท็บ
Frozen Flame

1
แต่ <div class = "group-condition" /> และ <div class = "condition" /> เหมือนกันสำหรับ $ x ('// div [มี (concat ("", normalize-space (@class), " ")," condition ")] ')
Memke

1
@ testerjoe2 ลอง//*[contains(concat(" ", normalize-space(@class), " "), " foo ")]รึยัง?
Niels Bom

11

//[@class="date"] ไม่ใช่ xpath ที่ถูกต้อง

ลอง//*[@class="date"]หรือถ้าคุณรู้ว่ามันเป็นภาพ//img[@class="date"]


7

XPath 3.1แนะนำฟังก์ชันมีโทเค็นและในที่สุดก็แก้ปัญหานี้อย่างเป็นทางการ มันถูกออกแบบมาเพื่อการเรียนการสนับสนุน

ตัวอย่าง:

//*[contains-token(@class, "foo")]

ฟังก์ชันนี้ทำให้แน่ใจว่าช่องว่าง (ไม่เพียง แต่(U + 0020)) ได้รับการจัดการอย่างถูกต้องใช้งานได้ในกรณีที่มีการซ้ำชื่อคลาสและโดยทั่วไปครอบคลุมขอบกรณี


หมายเหตุ:ณ วันนี้ (2016/12/13) XPath 3.1 มีสถานะของผู้สมัครคำแนะนำ


มันไม่ทำงานใน Chrome ล่าสุดของวันนี้ จนกว่าจะได้ผลเราจะหลีกเลี่ยงข้อ จำกัด ที่ // * [มี (@class, "foo")] ยังจะเลือกคลาสใดก็ได้ที่มี foo เช่น foobar, fooz เป็นต้น
MasterJoe

3

ใน XPath 2.0 คุณสามารถ:

//*[count(index-of(tokenize(@class, '\s+' ), 'foo')) = 1]

ตามที่ Christian Weiske ระบุใน: https://cweiske.de/tagebuch/XPath%3A%20Select%20element%20by%20class.htm


ขออภัยดูเหมือนว่า Chrome จะไม่สามารถใช้งานได้ในวันที่ 6/12/2017 อ้างอิงจากen.wikipedia.org/wiki/…ดูเหมือนว่าจะขาดกันไป
พอสมควร

1

HTML อนุญาตให้ใช้องค์ประกอบที่ไม่คำนึงถึงขนาดตัวพิมพ์และชื่อแอตทริบิวต์จากนั้นคลาสจะเป็นรายการชื่อคลาสที่คั่นด้วยช่องว่าง ที่นี่เราไปหาimgแท็กและclassชื่อdate:

//*['IMG' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')]/@*['CLASS' = translate(name(.), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') and contains(concat(' ', normalize-space(.), ' '), concat(' ', 'date', ' '))]

ดูด้วย: CSS Selector เป็นการแปลง XPath


1

ระวังเครื่องหมายลบในเทมเพลต !!! หากคุณกำลังค้นหา "my-ownclass" ใน DOM:

<ul class="my-ownclass"><li>...</li></ul>
<ul class="someother"><li>...</li></ul>
<ul><li>...</li></ul>

$finder = new DomXPath($dom);
$nodes = $finder->query(".//ul[contains(@class, 'my-ownclass')]"); // This will NOT behave as expected! This will strangely match all the <ul> elements in DOM.
$nodes = $finder->query(".//ul[contains(@class, 'ownclass')]"); // This will match the element.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.