ฉันใช้PHP DOMและฉันกำลังพยายามรับองค์ประกอบภายในโหนด DOM ที่มีชื่อคลาสที่กำหนด วิธีที่ดีที่สุดในการรับองค์ประกอบย่อยนั้นคืออะไร
อัปเดต:ฉันลงเอยด้วยการใช้Mechanize
PHP ซึ่งทำงานได้ง่ายกว่ามาก
ฉันใช้PHP DOMและฉันกำลังพยายามรับองค์ประกอบภายในโหนด DOM ที่มีชื่อคลาสที่กำหนด วิธีที่ดีที่สุดในการรับองค์ประกอบย่อยนั้นคืออะไร
อัปเดต:ฉันลงเอยด้วยการใช้Mechanize
PHP ซึ่งทำงานได้ง่ายกว่ามาก
คำตอบ:
อัปเดต: *[@class~='my-class']
ตัวเลือก css เวอร์ชัน Xpath
ดังนั้นหลังจากที่ความคิดเห็นของฉันด้านล่างในการตอบสนองต่อความคิดเห็น hakre Zend_Dom_Query
ผมอยากรู้อยากเห็นและมองเข้าไปในรหัสที่อยู่เบื้องหลัง ดูเหมือนว่าตัวเลือกด้านบนจะคอมไพล์กับ xpath ต่อไปนี้ (ยังไม่ทดลอง):
[contains(concat(' ', normalize-space(@class), ' '), ' my-class ')]
ดังนั้น php จะเป็น:
$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
โดยพื้นฐานแล้วสิ่งที่เราทำที่นี่คือทำให้class
แอตทริบิวต์เป็นมาตรฐานเพื่อให้แม้แต่คลาสเดียวถูกล้อมรอบด้วยช่องว่างและรายการคลาสทั้งหมดจะถูกล้อมรอบด้วยช่องว่าง จากนั้นต่อท้ายชั้นเรียนที่เรากำลังค้นหาด้วยช่องว่าง ด้วยวิธีนี้เรากำลังมองหาและพบเฉพาะกรณีของmy-class
.
ใช้ตัวเลือก xpath?
$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(@class, '$classname')]");
หากเป็นองค์ประกอบเพียงประเภทเดียวคุณสามารถแทนที่*
ด้วย tagname เฉพาะได้
หากคุณต้องการทำสิ่งนี้ให้มากด้วยตัวเลือกที่ซับซ้อนมากฉันขอแนะนำZend_Dom_Query
ซึ่งรองรับไวยากรณ์ตัวเลือก CSS (a la jQuery):
$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");
my-class2
เหมือนกัน แต่สวยหวาน มีวิธีใดในการเลือกเฉพาะองค์ประกอบแรกของทั้งหมด?
class
สามารถมีได้มากกว่าหนึ่งคลาสเช่น<a class="my-link link-button nav-item">
.
//*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')]
(ข้อมูลมาก: CSS Selectors และนิพจน์ XPath )
contains
ร่วมกับconcat
... เรากำลังพูดคุยเกี่ยวกับรายละเอียดของการเพิ่มช่องว่างทั้งสองด้านของชั้นเรียนที่คุณกำลังค้นหาหรือเพิ่มเพียงด้านเดียว ควรใช้อย่างใดอย่างหนึ่ง
หากคุณต้องการรับ innerhtml ของคลาสโดยไม่มี zend คุณสามารถใช้สิ่งนี้:
$dom = new DomDocument();
$dom->load($filePath);
$classname = 'main-article';
$finder = new DomXPath($dom);
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
$tmp_dom = new DOMDocument();
foreach ($nodes as $node)
{
$tmp_dom->appendChild($tmp_dom->importNode($node,true));
}
$innerHTML.=trim($tmp_dom->saveHTML());
echo $innerHTML;
$classname = 'main-article'
ฉันคิดว่าวิธีที่ได้รับการยอมรับนั้นดีกว่า แต่ฉันคิดว่าวิธีนี้อาจได้ผลเช่นกัน
function getElementByClass(&$parentNode, $tagName, $className, $offset = 0) {
$response = false;
$childNodeList = $parentNode->getElementsByTagName($tagName);
$tagCount = 0;
for ($i = 0; $i < $childNodeList->length; $i++) {
$temp = $childNodeList->item($i);
if (stripos($temp->getAttribute('class'), $className) !== false) {
if ($tagCount == $offset) {
$response = $temp;
break;
}
$tagCount++;
}
}
return $response;
}
$classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
นอกจากนี้ยังมีวิธีการอื่นโดยไม่ใช้หรือDomXPath
Zend_Dom_Query
จากฟังก์ชันดั้งเดิมของ dav ฉันเขียนฟังก์ชันต่อไปนี้ที่ส่งคืนลูกทั้งหมดของโหนดแม่ที่มีแท็กและคลาสตรงกับพารามิเตอร์
function getElementsByClass(&$parentNode, $tagName, $className) {
$nodes=array();
$childNodeList = $parentNode->getElementsByTagName($tagName);
for ($i = 0; $i < $childNodeList->length; $i++) {
$temp = $childNodeList->item($i);
if (stripos($temp->getAttribute('class'), $className) !== false) {
$nodes[]=$temp;
}
}
return $nodes;
}
สมมติว่าคุณมีตัวแปร$html
HTML ต่อไปนี้:
<html>
<body>
<div id="content_node">
<p class="a">I am in the content node.</p>
<p class="a">I am in the content node.</p>
<p class="a">I am in the content node.</p>
</div>
<div id="footer_node">
<p class="a">I am in the footer node.</p>
</div>
</body>
</html>
การใช้งานgetElementsByClass
ทำได้ง่ายเพียงแค่:
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($html);
$content_node=$dom->getElementById("content_node");
$div_a_class_nodes=getElementsByClass($content_node, 'div', 'a');//will contain the three nodes under "content_node".
DOMDocumentพิมพ์ช้าและphpQueryมีปัญหาหน่วยความจำรั่ว ฉันลงเอยด้วยการใช้:
https://github.com/wasinger/htmlpagedom
ในการเลือกชั้นเรียน:
include 'includes/simple_html_dom.php';
$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;
ฉันหวังว่านี่จะช่วยคนอื่นเช่นกัน