DOMDocument::loadHTML 错误

66

我编写了一个脚本,将页面上的所有CSS组合在一起以便在我的CMS中使用。它工作得很好,但现在出现了以下错误:


警告: DOMDocument::loadHTML() [domdocument.loadhtml]: Entity中的header标记无效,行号:10位于css.php的第26

警告: DOMDocument::loadHTML() [domdocument.loadhtml]: Entity中的nav标记无效,行号:10位于css.php的第26

警告: DOMDocument::loadHTML() [domdocument.loadhtml]: Entity中的section标记无效,行号:22位于css.php的第26

这是PHP脚本

这是我的代码:

<?php
header('Content-type: text/css');
include ('../global.php');

if ($usetpl == '1') {
    $client = New client();
    $tplname = $client->template();
    $location = "../templates/$tplname/header.php";
    $page = file_get_contents($location);
} else {
    $page = file_get_contents('../index.php');
}

class StyleSheets extends DOMDocument implements IteratorAggregate
{

    public function __construct ($source)
    {
        parent::__construct();
        $this->loadHTML($source);
    }

    public function getIterator ()
    {
        static $array;
        if (NULL === $array) {
            $xp = new DOMXPath($this);
            $expression = '//head/link[@rel="stylesheet"]/@href';
            $array = array();
            foreach ($xp->query($expression) as $node)
                $array[] = $node->nodeValue;
        }
        return new ArrayIterator($array);
    }
}

foreach (new StyleSheets($page) as $index => $file) {
    $css = file_get_contents($file);
    echo $css;
}

1
这个问题已经在 https://bugs.php.net/bug.php?id=60021 上报给了 PHP,进而在底层的 libxml2 中引发了一个功能请求:https://bugzilla.gnome.org/show_bug.cgi?id=761534。 - cweiske
5个回答

171

Header,Nav和Section是HTML5的元素。由于HTML5开发者认为记住公共标识符和系统标识符太困难了,所以文档类型声明只需如下:

<!DOCTYPE html>
换言之,没有DTD可以检查,这将使DOM使用HTML4 Transitional DTD,而该DTD不包含那些元素,因此会出现警告。为了抑制这些警告,请添加以下内容:
libxml_use_internal_errors(true);

在调用loadHTML之前

libxml_use_internal_errors(false);

在此之后。

另一个选择是使用https://github.com/html5lib/html5lib-php


3
做完了,现在我得到了一个空白页面。 - user1079160
3
@user1079160那是另一个问题!戈登已经给出了好的答案,谢谢! - Thomas Decaux
2
@Gordan,你如何解决空白页面问题? - CodeGuru
1
我遇到了相同的空白页面问题。我的错误是使用print $document->saveXML()而不是$document->saveHTML()。 HTML版本不会进行XML版本所做的某些格式转换。如果这不是问题,请尝试检查输出源以查看存在哪些标记(如果有)。它应该提示您了解底层发生的情况。此外,不要忘记使用var_dump - ndm13

24

使用DOMDocument对象时,你可以在load方法前面加上@符号来抑制所有警告。

$dom = new DOMDocument;
@$dom->loadHTML($source);

然后继续。


这是一个可怕的解决方案,因为你会在这一行上犯错误,导致调试成为噩梦。@Gordon的解决方案要好得多。 - Ahmad

14

虽然HTML5元素仍未受支持,但您可以通过$options参数完全消除libxml错误。

只需设置

$doc = new DOMDocument();
$doc->loadHTMLFile("html5.html", LIBXML_NOERROR);

相比于使用 @ 忽略 PHP 错误,这个选项更加推荐。

但是要小心,libxml 很宽容,即使解析错误的 HTML 文档也不会报错。如果你忽略 libxml 的错误信息,你可能不会意识到 HTML 是有问题的。


有没有选项只静音由于HTML 5元素而引发的错误? - jnbm
1
据我所知,没有。 - Dharman

1
大多数人并不意识到 HTML 和 XML 作为语言以及 HTML 和 XML 解析器之间的区别。解析器接受代码,而 HTML 和 XML 解析器完全不同。虽然 XML 解析器在浏览器中会容忍一些小问题(例如重复的 id 值),但它们不会处理看起来像代码的垃圾信息。
PHP 的 XML 解析器甚至更加严格,不允许重复的 id 值。此外,由于任何东西都可以是元素(例如 footer、header、section),PHP 的 XML 解析器不会抱怨未知的 HTML5+ 元素。
$dom->loadXML($xml);

如果您在客户端进行开发,我强烈建议使用XML解析器来处理您的HTML5代码,自从我在2000年代开始开发到2020年,Gecko浏览器(例如Waterfox、Firefox)拥有最好的XML解析器,因为整个页面将会崩溃,并且您将会收到一个明确的错误信息。更严格的代码可以产生更好的结果,如果您能理解质量最终会产生数量,但反过来则不成立。


0

不要使用DOMDocument,您可以考虑使用Symfony中的这个方便的DomCralwer组件:

https://symfony.com/doc/current/components/dom_crawler.html

composer require symfony/dom-crawler

然后你可以做很酷的事情,比如
$crawler = new Crawler($html);
$crawler->filter(".whatever .wild > .query  ~.you[name=it]")->each(function($node, $i){
    print_r($node->text());

    //or something like this
    $node->children()->each(function($node_inner, $j){
        ...
    });
    ...
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接