ক্লাস নাম অনুসারে DOM উপাদান প্রাপ্ত করা


124

আমি পিএইচপি ডম ব্যবহার করছি এবং আমি একটি ডোম নোডের মধ্যে একটি নির্দিষ্ট শ্রেণীর নাম রয়েছে এমন একটি উপাদান পাওয়ার চেষ্টা করছি। সেই উপ-উপাদানটি পাওয়ার সবচেয়ে ভাল উপায় কী?

আপডেট: আমি ব্যবহার শেষMechanize পিএইচপি যা দিয়ে কাজ করা অনেক সহজ ছিল।


উত্তর:


154

আপডেট: *[@class~='my-class']সিএসএস নির্বাচকের এক্সপাথ সংস্করণ

হ্যাকারের মন্তব্যের জবাবে নীচে আমার মন্তব্যের পরে, আমি কৌতূহলী হয়ে উঠি এবং পিছনের কোডটি সন্ধান করি Zend_Dom_Query। দেখে মনে হচ্ছে উপরের নির্বাচকটি নিম্নলিখিত xpath (অনির্ধারিত) তে সংকলিত হয়েছে:

[contains(concat(' ', normalize-space(@class), ' '), ' my-class ')]

সুতরাং পিএইচপি হবে:

$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


একটি এক্সপ্যাথ নির্বাচনকারী ব্যবহার করবেন?

$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(@class, '$classname')]");

যদি এটি কেবলমাত্র এক ধরণের উপাদান থাকে তবে আপনি *নির্দিষ্ট ট্যাগের সাথে এটি প্রতিস্থাপন করতে পারেন ।

আপনার যদি খুব জটিল সিলেক্টর এর সাথে প্রচুর পরিমাণে করার দরকার হয় তবে আমি সুপারিশ করব Zend_Dom_Queryযা সিএসএস নির্বাচক সিনট্যাক্স (একটি লা জিকুয়েরি) সমর্থন করে:

$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");

ক্লাসটিও খুঁজে পাওয়া যায় my-class2, তবে বেশ মিষ্টি। সমস্ত উপাদানগুলির মধ্যে প্রথমটি বেছে নেওয়ার কোনও উপায়?
হ্যাক্রে

আমি মনে করি না আপনি xpath2 ছাড়াই পারবেন ... তবে Zend_Dom_Query এর উদাহরণটি ঠিক এটি করে। যদি আপনি সেই প্রকল্পটি আপনার প্রকল্পে ব্যবহার করতে না চান তবে আপনি দেখতে চাইতে পারেন তারা কীভাবে সিএসএস নির্বাচককে এক্সপ্যাটে অনুবাদ করছেন। হতে পারে ডোমএক্সপাথ এক্সপথ ২.০ সমর্থন করে - আমি সে সম্পর্কে নিশ্চিত নই।
প্রোডিজিটালসন

1
কারণ classউদাহরণস্বরূপ একাধিক শ্রেণী থাকতে পারে: <a class="my-link link-button nav-item">
প্রোডিজিটালসন

2
@ প্রোডিজিটালসন: এটি ভুল কারণ এটি স্থানগুলি প্রতিফলিত করে না, চেষ্টা করুন //*[contains(concat(' ', normalize-space(@class), ' '), ' classname ')](খুব তথ্যপূর্ণ: সিএসএস নির্বাচক এবং এক্সপাথ এক্সপ্রেশন )।
hakre

1
@ বাবঙ্ক: হ্যাঁ, আপনার containsসাথে সম্মিলিতভাবে ব্যবহার করা দরকার concat... আমরা শ্রেণীর উভয় পাশের ফাঁকা জায়গাগুলির প্যাডিংয়ের বিবরণ আলোচনা করছি যা আপনি কেবল একপাশে সন্ধান করছেন বা কেবল প্যাডিং করছেন। হয় যদিও কাজ করা উচিত।
প্রোডিজিটালসন

20

আপনি যদি জেন্ড ছাড়া ক্লাসের অন্তর্নির্মিত HTML পেতে চান তবে আপনি এটি ব্যবহার করতে পারেন:

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

2
লাইনের জন্য সেমিকোলন হারিয়েছে$classname = 'main-article'
কামিল

12

আমি মনে করি গৃহীত উপায়টি আরও ভাল তবে আমি অনুমান করি এটি সম্ভবত কার্যকর হবে

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

2
এর উদাহরণ কোথায়? ভাল লাগত।
রোবু-এ 7119895

দারুণ. ক্লাস নিয়ে এলিমেন্ট পেয়েছি। এখন আমি ক্লাসযুক্ত উপাদানটিতে সন্তানের সংযোজনের মতো উপাদানটির বিষয়বস্তু সম্পাদনা করতে চাই। কীভাবে শিশুকে সংযোজন এবং পুরো এইচটিএমএল পুনরায় তৈরি করবেন? সাহায্য করুন. এটাই আমি করেছি। $classResult = getElementByClass($dom, 'div', 'm-signature-pad'); $classResult->nodeValue = ''; $enode = $dom->createElement('img'); $enode->setAttribute('src', $signatureImage); $classResult->appendChild($enode);
কিউর

1
পিএইচপি দ্বারা ডোম পরিবর্তনের আমি মনে করি তার ভাল ব্যবহার করার জন্য phpquery github.com/punkave/phpQuery
ডেভ

7

DomXPathবা ব্যবহার না করে অন্য পদ্ধতিও রয়েছেZend_Dom_Query

ডেভের মূল ফাংশনের উপর ভিত্তি করে, আমি নিম্নলিখিত ফাংশনটি লিখেছি যা প্যারেন্ট নোডের সমস্ত সন্তানকে ফিরিয়ে দেয় যাদের ট্যাগ এবং শ্রেণি প্যারামিটারগুলির সাথে মেলে।

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

6

DOMDocament টাইপ এবং phpQuery ধীর এর খারাপ মেমরি ফাঁসের সমস্যা রয়েছে। আমি ব্যবহার করে শেষ করেছি:

https://github.com/wasinger/htmlpagedom

একটি শ্রেণি নির্বাচন করতে:

include 'includes/simple_html_dom.php';

$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;

আমি আশা করি এটি অন্য কাউকেও সহায়তা করে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.