【问题标题】:How to loadHTMLFile() when it fails with 'htmlParseEntityRef: no name' error?当它因“htmlParseEntityRef:无名称”错误而失败时如何加载HTMLFile()?
【发布时间】:2013-06-25 12:19:04
【问题描述】:

我正在尝试将字符串“hinson lou ann”取出:

 <div class='owner-name'>hinson lou ann</div>

当我运行以下命令时:

$html = "http://gisapps.co.union.nc.us/ws/rest/v2/cm_iw.ashx?gid=12339";
$doc  = new DOMDocument();
$doc->loadHTMLFile($html);
$xpath    = new DOMXpath($doc);
$elements = $xpath->query("*/div[@class='owner-name']");
if (!is_null($elements)) {
    foreach ($elements as $element) {
        echo "<br/>[" . $element->nodeName . "]";
        $nodes = $element->childNodes;
        foreach ($nodes as $node) {

            echo $node->nodeValue . "\n";
        }
    }
}

我收到以下错误:

警告:DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef:http://gisapps.co.union.nc.us/ws/rest/v2/cm_iw.ashx?gid=12339 中没有名称,行:/home 中的 1...在线...

指的是loadHTMLFILE这一行。

注意:该文件不是有效的 HTML,它只包含 div 标记!什么是我加载文件然后在上面打了HTMLbody标签?

【问题讨论】:

  • 首先,那个输出不是有效的html。
  • 尝试$html = file_get_contents('http://gisapps.co.union.nc.us/ws/rest/v2/cm_iw.ashx?gid=12339'); 然后$doc-&gt;loadHTMLFile($html); ...这就是我至少抓取网页的方式
  • 是的,但@RobW 是对的,它不是有效的 html....只有 div 标签!任何想法
  • 这就是你的问题:HINSON J MARK &amp; WF LOU ANN G...&amp;amp; 启动一个实体,一个裸露的&amp;amp; 应该是&amp;amp;。嗯,$doc-&gt;recover=true; 和所有都是 'wellish'(前提是您使用 //div[@class='owner-name'] 而不是 */div[@class='owner-name'],因为它神奇地创建了元素以使其成为真正的 HTML)。
  • 下次也请教一个问题。你还没有问你关心什么。因此,用户只能猜测您提出的哪个问题导致了您。仅凭错误信息很难说。

标签: html dom xpath php


【解决方案1】:

远程站点可能会返回导致此警告的无效 HTML。 DOMDocument 和 DOMXPath 在 HTML 错误的情况下非常宽容。如果在调用 DOMDocument::loadHTML() 后只有一个警告,而其余代码产生有效结果,我建议您使用静默运算符 @ 抑制警告:

$doc = new DOMDocument();

// suppress warnings
$ret = @$doc->loadHTML($html);

// but check errors ...
if($ret === FALSE) {
    die('Parse error');
}

【讨论】:

  • 我试过这个没有运气。该文件不是有效的 HTML,它仅包含 div 标签
  • @Wrikken 你能解释一下吗?我希望recover 默认为true
  • @hek2mgl:好吧,我会的。注意:默认情况下它不是true(至少不是在这里),但是在这里设置(或不设置)它并没有那么好,我太仓促了,我很抱歉 :) (这里的实际问题是 DOMDocument 神奇地创建了 html 和 body 标记对 xpath 进行必要的更改)。
  • @Wrikken 感谢您的解释。 :) 我不得不承认我懒得仔细看 xpath 表达式..
【解决方案2】:

如果你真的必须尝试解析它,试试这个:

<?php
$html = file_get_contents("http://gisapps.co.union.nc.us/ws/rest/v2/cm_iw.ashx?gid=12339");
$doc = new DOMDocument();
$doc->strictErrorChecking = false;
$doc->recover=true;
@$doc->loadHTML("<html><body>".$html."</body></html>");

$xpath = new DOMXpath($doc);
$elements = $xpath->query("//*/div[@class='owner-name']");

if (!is_null($elements)) {
   foreach ($elements as $element) {
      echo "<br/>[". $element->nodeName. "]";
      $nodes = $element->childNodes;
      foreach ($nodes as $node) {
         echo $node->nodeValue. "\n";
     }
   }
 }
?>

PS:您的 XPath 错误,我已修复。您的 $nodes 将没有任何内容,因为该 DIV 元素 (.owner-name) 没有任何子元素。所以您需要修改它。

【讨论】:

    【解决方案3】:

    只需从源代码构建一个 HTML 文档,将其包装在缺少的元素中就可以了。

    例如:-

    <?php
    $html = file_get_contents('http://gisapps.co.union.nc.us/ws/rest/v2/cm_iw.ashx?gid=12339');
    $html = sprintf('<html><head><title></title></head><body>%s</body></html>', $html);
    
    $doc = new DOMDocument;
    $doc->loadHTML($html);
    
    $xpa    = new DOMXPath($doc);
    $divs   = $xpa->query('//div[@class="owner-name"]');
    
    foreach($divs as $div) {
        echo $div->nodeValue, PHP_EOL;
    }
    
    /*
        hinson lou ann
    */
    

    【讨论】:

      【解决方案4】:

      您收到错误是因为您加载的 HTML 包含 &amp; 字符,而不是有效的 HTML 实体。缺少实体的名称:

      ... <td>HINSON J MARK & WF LOU ANN G</td> ...
                            ^
      

      在加载此类文档时,您会在这些情况下看到错误(如您所写):

      警告:DOMDocument::loadHTMLFile(): htmlParseEntityRef: 无名

      name 与 HTML Entity (reference) 的名称相关,通过模式:

      &name;
       ^^^^
      

      但是,此错误不会导致实际加载该 HTML 出现任何问题。 DOMDocument 可以很好地处理这个(常见)错误(但是您可能会遇到a cut-off at the problematic position)。

      因此,您需要将该文件包装到 &lt;body&gt; 标记中的假设是错误的。在 HTML 中,&lt;body&gt; 标签是可选的。

      您的具体问题是您无法理解如何在加载 HTML 文件后对其进行调试。只需使用saveHTML method 输出可以成功加载的内容。这样做已经表明该 URL 已成功加载。

      接下来会引导您指出 Xpath 表达式是错误的:

      */div[@class='owner-name']
      

      尽管您对&lt;body&gt; 标记的了解并不遥远:即使该HTML 片段不包含&lt;body&gt; 标记,DOM 也会拥有它!虽然里面有两个标签:

      body/*/*/div[@class='owner-name']
      

      最常见的缩写形式是使用//,它允许不明确表示标签位于哪个深度:

      //div[@class='owner-name']
      

      参见:

      【讨论】:

        猜你喜欢
        • 2014-08-09
        • 2020-10-25
        • 2020-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多