Search code examples
phpdomdocument

How to set class to all text node parents inside of specific block


I need to set a class to parent of each text node inside of specific block on my page.

Here is what I'm trying to do:

$pageHTML = '<html><head></head>
<body>

<header>
  <div>
    <nav>Menu</nav>
    <span>Another text</span>
  </div>
</header>

<section>Section</section>
<footer>Footer</footer>
</body>
</html>';

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML($pageHTML);
libxml_use_internal_errors(false);

foreach($dom->getElementsByTagName('body')[0]->childNodes as $bodyChild) {

    if($bodyChild->nodeName == 'header') {

        $blockDoc = new DOMDocument();
        $blockDoc->appendChild($blockDoc->importNode($bodyChild, true));
        $xpath = new DOMXpath($blockDoc);

        foreach($xpath->query('//text()') as $textnode) {
            if(preg_match('/\S/', $textnode->nodeValue)) { // exclude non-characters
                 $textnode->parentNode->setAttribute('class','my_class');
            }
        }
    }
}

echo $dom->saveHTML((new \DOMXPath($dom))->query('/')->item(0));

I need to get <nav> and <span> inside of <header> with the my_class but I don't get.

As I can understand, I need to return back changed parents to DOM after setting the class to them, but how can I do that?


Solution

  • Ok, I've found the answer by myself:

    ...
    $xpath = new DOMXpath($dom);
    
    foreach($dom->getElementsByTagName('body')[0]->childNodes as $bodyChild) {
    
        if($bodyChild->nodeName == 'header') {
    
            foreach($xpath->query('.//text()', $bodyChild) as $textnode) {
    
                if(preg_match('/\S/', $textnode->nodeValue)) { // exclude non-characters
                    $textnode->parentNode->setAttribute('class','my_class');
                }
            }
        }
    }