Search code examples
phphtmlxpathdomdocument

PHP Extracting the Contents of a DIV Block with domdocument


Extract the contents of a DIV block. There are more blocks in the Div block. I want to retrieve some information. There are several Div blocks. It would be best if it could run into a foreach loop.

$dom_document = new DOMDocument();
libxml_use_internal_errors(true);
$dom_document->loadHTML($html);
libxml_clear_errors();
$dom_document->preserveWhiteSpace = false;

//use DOMXpath to navigate the html with the DOM
$xpath = new DOMXpath($dom_document);

$items = $xpath->query('//div[contains(@class,"card")]');
foreach ($items as $item) {

   $title = $xpath->xpath('.//div[@class="card-header"]/div/a[@class="text-number"]');

}

echo $title;

Der HTML-Code dazu:


        <div class="row">
          <div class="col-xl-4 col-lg-6 col-md-6 col-smr-2 my-12 col-xs-12 mt-2 mb-3">
                    <div class="card">
                      <div class="card-header">
                        <div class="d-flex mb-2"><a class="text-number" href="/read/3325" id="3325">NUMBER</a>
                          </div>
                        </div>
                        <div class="d-flex">
                          <h5><a class="mr-auto" href="LINK" target="_blank">TITLE</a>
                          </h5>
                        </div>
                        <div class="d-flex"> <strong class="mr-2">AUTOR</strong><span class="mr-2">RANDOM-NUMBER</span>
                          <time class="text-muted mr-2" datetime="2019-04-26T01:20:28.000Z">TIME</time>
                        </div>
                      </div>
                      <div class="card-body">
                        <div class="card-text">CONTENT</div>
                      </div>
                    </div>
          </div>
          <div class="col-xl-4 col-lg-6 col-md-6 col-smr-2 my-12 col-xs-12 mt-2 mb-3">
                    <div class="card">
                      <div class="card-header">
                        <div class="d-flex mb-2"><a class="text-number" href="/read/3325" id="3325">NUMBER</a>
                          </div>
                        </div>
                        <div class="d-flex">
                          <h5><a class="mr-auto" href="LINK" target="_blank">TITLE</a>
                          </h5>
                        </div>
                        <div class="d-flex"> <strong class="mr-2">AUTOR</strong><span class="mr-2">RANDOM-NUMBER</span>
                          <time class="text-muted mr-2" datetime="2019-04-26T01:20:28.000Z">TIME</time>
                        </div>
                      </div>
                      <div class="card-body">
                        <div class="card-text">CONTENT</div>
                      </div>
                    </div>
          </div>
          <div class="col-xl-4 col-lg-6 col-md-6 col-smr-2 my-12 col-xs-12 mt-2 mb-3">
                    <div class="card">
                      <div class="card-header">
                        <div class="d-flex mb-2"><a class="text-number" href="/read/3325" id="3325">NUMBER</a>
                          </div>
                        </div>
                        <div class="d-flex">
                          <h5><a class="mr-auto" href="LINK" target="_blank">TITLE</a>
                          </h5>
                        </div>
                        <div class="d-flex"> <strong class="mr-2">AUTOR</strong><span class="mr-2">RANDOM-NUMBER</span>
                          <time class="text-muted mr-2" datetime="2019-04-26T01:20:28.000Z">TIME</time>
                        </div>
                      </div>
                      <div class="card-body">
                        <div class="card-text">CONTENT</div>
                      </div>
                    </div>
          </div>
          </div>

I need the following information - NUMBER - LINK - TITLE - AUTOR - RANDOM-NUMBER - TIME - CONTENT

I'm very grateful for your help. If someone knew about it it would be great.


Solution

  • It's a case of having to pick the individual elements from the XML starting inside each $item that you get.

    Using DOMDocument, it's easier to stick to using XPath expressions, but using descendant:: to ensure that the nodes searched are within the start element which is specified as the third parameter to evaluate(). As each point you want a string value - I've used evaluate('string(...)) as this will return a string whereas query() will return a DOMNodeList, which you then need to process.

    I hope the XPath makes sense given the above, the only oddity is the CONTENT. As this is the next node (and not a child node) I use following-sibling:: to access it.

    $items = $xpath->query('//div[@class="card"]');
    foreach ($items as $item) {
        $title = $xpath->evaluate('string(descendant::*//a[@class="text-number"])', $item);
        $link = $xpath->evaluate('string(descendant::div[@class="d-flex"][1]/h5/a/@href)', $item);
        $title = $xpath->evaluate('string(descendant::div[@class="d-flex"][1]/h5/a)', $item);
        $autor = $xpath->evaluate('string(descendant::div[@class="d-flex"][2]/strong)', $item);
        $randomNumber = $xpath->evaluate('string(descendant::div[@class="d-flex"][2]/span)', $item);
        $time = $xpath->evaluate('string(descendant::div[@class="d-flex"][2]/time)', $item);
        $content = $xpath->evaluate('string(following-sibling::*//div[@class="card-text"])', $item);
    
        echo $title."/".$link."/".$title."/".$autor."/".$randomNumber.
            "/".$time."/".$content.PHP_EOL;
    }
    

    For more info on things like descendant:: and following-sibling::, they are XPath Axes which are talked about here.