【问题标题】:Why do these two DOMDocument functions behave differently?为什么这两个 DOMDocument 函数的行为不同?
【发布时间】:2020-01-27 21:01:24
【问题描述】:

这里推荐了两种获取 DOMDocument 节点的外部 HTML 的方法:How to return outer html of DOMDocument?

我对为什么他们似乎以不同的方式对待 HTML 实体很感兴趣。

示例:

function outerHTML($node) {
    $doc = new DOMDocument();
    $doc->appendChild($doc->importNode($node, true));
    return $doc->saveHTML();
}

$html = '<p>ACME&rsquo;s 27&rdquo; Monitor is $200.</p>';
$dom = new DOMDocument();
@$dom->loadHTML($html);
$el = $dom->getElementsByTagname('p')->item(0);
echo $el->ownerDocument->saveHtml($el) . PHP_EOL;
echo outerHTML($el) . PHP_EOL;

输出:

<p>ACME’s 27” Monitor is $200.</p>
<p>ACME&rsquo;s 27&rdquo; Monitor is $200.</p>

这两种方法都使用saveHTML(),但由于某种原因,该函数在最终输出中保留了html实体,而使用节点上下文直接调用saveHTML()则没有。谁能解释为什么 - 最好有某种权威参考?

【问题讨论】:

标签: php html domdocument html-entities


【解决方案1】:

这比上面的测试用例更简单:

<?php
$html = '<p>ACME&rsquo;s 27&rdquo; Monitor is $200.</p>';
$dom = new DOMDocument();
@$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

echo $dom->saveHtml($dom->documentElement) . PHP_EOL;
echo $dom->saveHtml() . PHP_EOL;

那么问题就变成了,为什么DomDocument::saveHtml 在保存整个文档而不是仅保存特定节点时表现不同?

查看 PHP 源代码,我们发现 a check 是用于单个节点还是整个文档。对于前者,调用 htmlNodeDumpFormatOutput 函数时将编码显式设置为 null。对于后者,使用htmlDocDumpMemoryFormat 函数,编码不包含在该函数的参数中。

这两个函数都来自 libxml2 库。查看那个源代码,我们可以看到htmlDocDumpMemoryFormat tries to detect the document encoding,如果找不到,则将其显式设置为ASCII/HTML。

这两个函数最终都会调用htmlNodeListDumpOutput,并将已确定的编码传递给它;要么是 null - 导致不编码 - 要么是 ASCII/HTML - 使用 HTML 实体进行编码。

我的猜测是,对于文档片段或单个节点,编码被认为不如完整文档重要。

【讨论】:

  • “我的猜测是,对于文档片段或单个节点,编码被认为不如完整文档重要。” - 哈哈哈.. 这是有效的推测,但如果真的是这样,我会请求不同。无论如何,感谢您的研究。你认为这些是让saveHtml() 产生相同输出的任何方法,而不管上下文节点与否?
  • 我遇到了一堆问题,询问如何在有/没有实体的情况下进行输出。最好的办法是像 mb_convert_encoding($dom-&gt;saveHtml(), 'UTF-8', 'HTML-ENTITIES') 那样摆脱实体。
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 2012-09-21
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
相关资源
最近更新 更多