【问题标题】:Error when parsing DOMDocument with PHP使用 PHP 解析 DOMDocument 时出错
【发布时间】:2018-11-21 18:38:23
【问题描述】:

我们正在将我们的软件升级到 PHP 7.2.3,我有以下代码 sn-p 在以前的版本中运行良好:

$doc = new DOMDocument();
$doc->loadHTML("<html><body>".($_POST['reportForm_structure'])."</body></html>");

$root = $doc->documentElement->firstChild->firstChild->firstChild;
file_put_contents('D:\testoutput.txt', print_r($root ,true));

foreach($root->childNodes as $child) {
        if ($child->nodeName == "ul") {
            foreach($child->childNodes as $ulChild) {
                $this->loadNodes($ulChild, $this->report);
            }
        }           
    }

file_put_contents仅用于错误研究。

我收到以下错误:Invalid argument supplied for foreach()。该消息指的是第一个 foreach 循环所在的代码行。所以数据结构没有正确初始化。我可以看到从 HTML 到 DOMDocument 的转换不再正常工作。当我检查 file_put_contents 的输出时,我可以看到 $root 是一个 DOMText 对象而不是 DOMElement 对象,但是 why? 什么时候将loadHTML的参数直接传给file_put_contents

file_put_contents('D:\testoutput.txt', print_r("<html><body>".($_POST['reportForm_structure'])."</body></html>", true);

输出看起来像正确的 HTML,这就是为什么我对我不再工作感到困惑。

<html><body><ul class="ltr">
<li class="open last" id="root" rel="root">
    <a href="#"><ins>&nbsp;</ins>HeaderText</a>
<ul><li class="open last" id="id1" rel="header"><a href="#"><ins>&nbsp;</ins>Test123</a>
<ul><li class="open leaf last" id="id2" rel="header"><a class="clicked" href="#"><ins>&nbsp;</ins>Test456</a></li></ul></li></ul></li>

有谁知道如何解决这个问题。我在这里的配置中遗漏了什么吗?

【问题讨论】:

  • 你为什么不使用 $root = $dom->getElementById("root");获取具有根 id 的元素?
  • 你到底想要达到什么目的?

标签: php dom html-parsing domdocument php-extension


【解决方案1】:

感谢@Gordon 和@DarsVaeda 为我指明了正确的方向。 DOMDocument 将回车和制表符解释为文本节点。我不得不删除它们以使其再次工作。改变了

$doc->loadHTML("<html><body>".$_POST['reportForm_structure']."</body></html>");

$doc = new DOMDocument();       
$string = trim(preg_replace('/\t+/', '', $_POST['reportForm_structure']));
$string = preg_replace( "/\r|\n/", "", $string );       
$doc->loadHTML("<html><body>".$string."</body></html>");

【讨论】:

  • 我不明白你为什么要这样做而不是 $root = $doc->getElementById("root");这更精确。
  • @Gordon 我同意你的看法。关于为什么你要问这个我已经退休的前任,他实施了这个。我不知道他为什么使用firstChild 而不是getElementById
  • 我对你的前任为什么用firstChild 这样做并不感兴趣。我责怪缺乏经验。我更感兴趣的是为什么决定像你现在所做的那样更改代码,而不是使用你认为更好用的getElementById ;)
  • 谁说我在loadHTML 现在可以正常工作后没有使用getElementById? ;)
  • 但是如果你使用getElementById,你不需要去掉回车和制表符。
【解决方案2】:

我无法使用您显示的代码重现 DOMText 节点。但我的猜测是,您要保留空白,然后获取 ul 元素和 li 元素之间的空白节点。

                            v-------- whitespace node
<html><body><ul class="ltr">
<li class="open last" id="root" rel="root">

无论如何,如果您想要 ID 为“root”的元素,请使用更精确的查询,例如使用

$root = $doc->getElementById("root");

您也可以设置$doc-&gt;preserveWhiteSpace = false,但最好通过ID查询节点,而不是遍历三个子节点并假设它是那个节点。

【讨论】:

  • 我顶这个。我敢打赌,有一些空格之前被忽略了。 loadHtml 有一个选项可以忽略空节点,即
  • 感谢您的回复。我现在使用了$doc-&gt;preserveWhiteSpace = false; 选项,但它仍然不起作用。此外,根元素(html 节点)的选择以及body 节点的选择工作正常,但从那里向下没有任何作用。看起来 loadHtml 将其解释为纯文本。
  • @NewToSoap I cannot reproduce your issue。您的 POST 数据可能不是您认为的那样存在问题。考虑 var_dump'ing POST 数据并将其添加到您的问题中。或者提供$doc->saveHtml()的输出;
  • @Gordon,感谢您的努力。 $doc-&gt;saveHtml() 输出:&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt; &lt;html&gt;&lt;body&gt;&lt;ul class="ltr"&gt; &lt;li class="open last" id="root" rel="root"&gt; &lt;a href="#"&gt;&lt;ins&gt;&amp;nbsp;&lt;/ins&gt;TestHeader&lt;/a&gt; &lt;ul&gt;&lt;li class="open last" id="id1" rel="header"&gt;&lt;a href="#"&gt;&lt;ins&gt;&amp;nbsp;&lt;/ins&gt;Test123&lt;/a&gt;&lt;ul&gt;&lt;li class="open leaf last" id="id2" rel="header"&gt;&lt;a class="clicked" href="#"&gt;&lt;ins&gt;&amp;nbsp;&lt;/ins&gt;New Heading&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt; &lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;
  • @NewToSoap 仍然没有复制3v4l.org/MhcZ6。请echo $doc-&gt;saveHtml($root) 看看那个节点是什么。
猜你喜欢
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 2013-02-08
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多