第一个getElementsByTagName()返回HTML中的所有元素(奇怪的行为)


First getElementsByTagName() returns all elements in HTML (Strange behaviour)

我正在使用PHP解析Wordpress提供给我的HTML。

这是一篇帖子的PHP返回了我的Wordpress:

<p>Test</p> 
<p>
    <img class="alignnone size-thumbnail wp-image-39" src="img.png"/>
</p> 
<p>Ok.</p>

这是我的解析函数(还有调试):

function get_parsed_blog_post()
{
    $html = ob_wp_content(false);
    print_r(htmlspecialchars($html));
    echo '<hr/><hr/><hr/>';
    $parse = new DOMDocument();
    $parse->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXpath($parse);
    $ps = $xpath->query('//p');
    foreach ($ps as $p) 
    {
        $imgs = $p->getElementsByTagName('img');
        print($imgs->length);
        echo '<br/>';
        if ($imgs->length > 0)
        {
            $p->setAttribute('class', 'image-content');
            foreach ($imgs as $img)
            {
                $img->removeAttribute('class');
            }
        }        
    }
    $htmlFinal = $parse->saveHTML();
    print_r(htmlspecialchars($htmlFinal));
    echo '<hr/><hr/><hr/>';
    return $htmlFinal;
}

此代码的目的是删除Wordpress添加到<img>的类,并将任何包含图像的<p>设置为image-content的类。

这个返回:

1
1
0
<p class="image-content">Test
<p class="image-content">
    <img src="img.png">
</p>
<p>Ok.</p></p>

不知怎的,它将第一次出现的<p>包裹在我解析的整个帖子中,导致第一个<p>错误地应用了image-content类。为什么会发生这种情况?我该如何阻止它?

方法1

至于使用您的代码,我已经做了一些更改以使其正常工作。

若您打印出每个$p,您将能够看到第一个元素将包含所有HTML。最简单的解决方案是在HTML之前添加一个空白的<p>,并在foreach时跳过它。

function get_parsed_blog_post()
{
    $page_content_html = ob_wp_content(false);
    $html = "<p></p>".$page_content_html;
    print_r(htmlspecialchars($html));
    echo '<hr/><hr/><hr/>';
    $parse = new DOMDocument();
    $parse->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXpath($parse);
    $ps = $xpath->query('//p');
    $i = 0;
    foreach ($ps as $p) 
    {
        if($i != 0) {
            $imgs = $p->getElementsByTagName('img');
            print($imgs->length);
            echo '<br/>';
            if ($imgs->length > 0)
            {
                $p->setAttribute('class', 'image-content');
                foreach ($imgs as $img)
                {
                    $img->removeAttribute('class');
                }
            }
        }
        $i++;
    }
    $htmlFinal = $parse->saveHTML();
    print_r(htmlspecialchars($htmlFinal));             
    echo '<hr/><hr/><hr/>';
    return $htmlFinal;
}

总执行时间(以秒为单位):0.0003499987412109

方法2

这个问题是由LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD引起的(它也将第一个<p>作为父级),但您可以在没有这个的情况下删除文档标记。所以,你可以在这里这样做:

function get_parsed_blog_post()
{
$page_content_html = ob_wp_content(false);
$doc = new DOMDocument();
$doc->loadHTML($page_content_html);
foreach($doc->getElementsByTagName('p') as $paragraph) {
    $imgs = $paragraph->getElementsByTagName('img');
    if ($imgs->length > 0)
    {
        $paragraph->setAttribute('class', 'image-content');
        foreach ($imgs as $img)
        {
            $img->removeAttribute('class');
        }
    }        
}

/* REMOVING DOCTYPE, HTML AND BODY TAGS */
// Removing DOCTYPE
$doc->removeChild($doc->doctype);
// Removing HTML tag
$doc->replaceChild($doc->firstChild->firstChild, $doc->firstChild);
// Removing Body Tag
$html = $doc->getElementsByTagName("body")->item(0);
$fragment = $doc->createDocumentFragment();
while ($html->childNodes->length > 0) {
    $fragment->appendChild($html->childNodes->item(0));
}
$html->parentNode->replaceChild($fragment, $html);
$htmlFinal = $doc->saveHTML();
print_r(htmlspecialchars($htmlFinal));             
echo '<hr/><hr/><hr/>';
return $htmlFinal;
}

总执行时间(秒):0.00026822090148926