开发者

Why does getElementsByTagName only grab every other element here?

With this code using DomDocument:

<?php
$html = '<pre>one</pre><pre>two</pre><pre>three</pre><pre&g开发者_运维技巧t;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();
?>

I get this output:

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

Working (or not) example

Can someone explain to me what is going on and why all the pre tags aren't being replaced?


You can try this way: 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();
?>

I found the issue when I googled "DomDocument replacechild" without the quotes

see the first comment here: http://php.net/manual/en/domnode.replacechild.php particularly this:

If you are trying to replace more than one node at once, you have to be careful about iterating over the DOMNodeList. If the old node has a different name from the new node, it will be removed from the list once it has been replaced. Use a regressive loop:


It has something to do with the direction:

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);
}

doesn't work but

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);
}

works fine. There must be something like an internal counter, I reckon.

HTH Andreas

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜