为什么getElementsByTagName只抓取这里的其他元素?


Why does getElementsByTagName only grab every other element here?

下面的代码使用DomDocument:

<?php
$html = '<pre>one</pre><pre>two</pre><pre>three</pre><pre>four</pre>';
$doc = new DomDocument();
$doc->loadHTML($html);
$sub = $doc->getElementsByTagName("pre");
foreach($sub as $pre) {
    $fragment = $doc->createDocumentFragment(); 
    $fragment->appendXML(str_replace('&', '&amp;', '<p>& it''s replaced</p>'));
    $pre->parentNode->replaceChild($fragment, $pre);
}
echo $doc->saveHTML();
?>

我得到这样的输出:

<p>& it's replaced</p> 
<pre>two</pre>
<p>& it's replaced</p>
<pre>four</pre>

工作(或不工作)示例

有人能向我解释一下发生了什么,为什么所有的pre标签没有被替换?

您可以这样尝试:http://codepad.viper-7.com/ALYWEi

<?php
$html = '<pre>one</pre><pre>two</pre><pre>three</pre><pre>four</pre>';
$doc = new DomDocument();
$doc->loadHTML($html);
$sub = $doc->getElementsByTagName("pre");
$i = $sub->length - 1;
while ($i > -1) {
    $pre = $sub->item($i);
    $fragment = $doc->createDocumentFragment(); 
    $fragment->appendXML(str_replace('&', '&amp;', '<p>& it''s replaced</p>'));

    $pre->parentNode->replaceChild($fragment, $pre);
    $i--;
} 
echo $doc->saveHTML();
?>

我发现这个问题,当我搜索"DomDocument replacechild"没有引号

见这里的第一条注释:http://php.net/manual/en/domnode.replacechild.php特别是这个:

如果您试图一次替换多个节点,则必须小心遍历DOMNodeList。如果旧节点的名称与新节点不同,则在替换后将其从列表中删除。使用一个回归循环:

这与方向有关:

for ($i = 0; $i < $sub->length; $i++) {
    $pre = $sub->item($i);
    $fragment = $doc->createDocumentFragment();
    $fragment->appendXML(str_replace('&', '&amp;', '<p>& it''s replaced</p>'));
    $pre->parentNode->replaceChild($fragment, $pre);
}

不工作,但

for ($i = $sub->length -1; $i >=0; $i--) {
    $pre = $sub->item($i);
    $fragment = $doc->createDocumentFragment();
    $fragment->appendXML(str_replace('&', '&amp;', '<p>& it''s replaced</p>'));
    $pre->parentNode->replaceChild($fragment, $pre);
}

工作好。我想这里面一定有一个类似内部计数器的东西。

HTH Andreas