为什么这个DOMDocument代码在尝试重新排列元素时不起作用?

时间:2011-03-09 06:36:29

标签: php html domdocument

我正试图以这种模式获取HTML ...

<p>a</p>
<p>b</p>
<p>c</p>
...
<h3>title</h3>

<p>e</p>
<p>e</p>
<p>f</p>
...
<h3>title2</h3>
...

......然后把它变成......

<ul>
  <li>
     <blockquote>
        <p>a</p>
        <p>b</p>
        <p>c</p>
        <cite>title</cite>
     </blockquote>
  </li>
  <li>
     <blockquote>
        <p>d</p>
        <p>e</p>
        <p>f</p>
        <cite>title2</cite>
     </blockquote>
  </li>
</ul>

我的PHP代码是......

$dom = new DOMDocument('1.0', 'utf-8');

$dom->preserveWhiteSpace = FALSE;

$dom->loadHTML($content);

$ul = $dom->createElement('ul');

$body = $dom->getElementsByTagName('body')->item(0);

$blockquote = FALSE;

foreach($body->childNodes as $element) {

    if ($element->nodeType != XML_ELEMENT_NODE) {
        continue;
    }

    if ( ! $blockquote) {
        $blockquote = $dom->createElement('blockquote');
        $li = $dom->createElement('li');
    }

    switch ($element->nodeName) {

        case 'p':
            $blockquote->appendChild($element);

            break;
        case 'h3':
            $li->appendChild($blockquote);

            $ul->appendChild($li);

            $blockquote = $li = FALSE;
            break;

    }
}

$body->appendChild($ul); 
echo $dom->saveHTML();

虽然功能尚未完成,但我注意到当我添加$blockquote->appendChild($element)时循环停止。

如果删除所有appendChild内容,则循环正常。

我的猜测是,通过在迭代中移动当前元素,它会打破循环。

我怎样才能让它发挥作用?

2 个答案:

答案 0 :(得分:1)

如果在插入当前文档时出现窒息,您是否考虑过创建新文档?您可以使用DOMDocument上的importNode方法将旧文档中的正确位复制到您将在新文档中创建的正确结构中。

您可以使用document fragment使用类似的技巧,只使用序列化的XML而不是使用节点对象。这可能适用于段落标记,至少。

答案 1 :(得分:1)

你的猜测是正确的。因为childNodes反映了当前的DOM,所以以你正在进行的方式移动元素会混淆循环。

我过去成功使用过的一种技术(尽管我从未尝试过使用php)是以相反的顺序遍历childNodes。因为您将节点附加到childNodes列表的末尾,这意味着您始终使用自循环开始以来尚未移动的元素。

显然,您需要稍微更改ul / li / blockquote构造逻辑以允许进行逆序处理。