除非使用htmlentities(),否则使用URL更新DOMAttr值会导致参数丢失。为什么?

时间:2014-08-24 20:18:27

标签: php domdocument domxpath

我正在尝试修改包含HTML的字符串中的链接,但我发现修改后的网址缺少参数。

示例:

$html = '
<p>
    <a href="http://example.com?foo=bar&bar=foobar">Example 1</a>
</p>';

libxml_use_internal_errors(true);
$dom = new \DOMDocument();
$dom->loadHTML($html);
$xpath = new \DOMXPath($dom);

foreach ($xpath->query('//a/@href') as $node) {
    echo '$node->nodeValue: ' . $node->nodeValue . PHP_EOL;
    $newValue = 'http://example2.com?foo=bar&bar=foobar';
    echo '$newValue: ' . $newValue . PHP_EOL;
    $node->nodeValue = $newValue;
    echo '$node->nodeValue: ' . $node->nodeValue . PHP_EOL;
}

输出:

$node->nodeValue: http://example.com?foo=bar&bar=foobar
$newValue: http://example2.com?foo=bar&bar=foobar
$node->nodeValue: http://example2.com?foo=bar

如您所见,更新nodeValue后第二个参数将丢失。

在尝试实验时,我尝试将$newValue更改为:

$newValue = htmlentities('http://example2.com?foo=bar&bar=foobar');

然后输出变为:

$node->nodeValue: http://example.com?foo=bar&bar=foobar
$newValue: http://example2.com?foo=bar&amp;bar=foobar
$node->nodeValue: http://example2.com?foo=bar&bar=foobar

为什么新节点值必须通过htmlentities()

运行

1 个答案:

答案 0 :(得分:1)

&符号是XML / HTML中的保留字符 - 它们开始字符引用。如果你试图将它们直接写入DOM中的字符串,那么事情往往会爆炸,因为DOM不知道你想说什么。当您首先使用htmlentities()时,它会对“&amp;”进行编码每个人都在说同一种语言。

幸运的是,根本不需要htmlentities()。不要直接设置nodeValue,而是使用href所有者的setAttribute()方法。


而不是:

$node->nodeValue = $newValue;

使用:

$node->ownerElement->setAttribute('href', $newValue);

直接操作DOM中的字符串可能会导致问题甚至不一定在系统中表现出来。我没有丢失您的示例参数,我丢失了整个网址。

我强烈建议尽可能坚持使用setter。