在PHP中,为什么我必须在DOMNode上执行两次removeChild方法,我刚刚删除了style-attribute?

时间:2010-09-07 16:32:44

标签: php html dom

我在PHP中有一个脚本,它从HTML文件中删除空段落。空段落是那些没有textContent的<p></p>元素。

包含空段落的HTML文件:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!--
This page is used with remove_empty_paragraphs.php script.
This page contains empty paragraphs. The script removes the empty paragraphs and
writes a new HTML file.
-->
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title></title>
    </head>
    <body>
        <p>This is a paragraph.</p>
        <!-- Below is an empty paragraph. -->
        <p><span></span></p>
        <p>This is another paragraph.</p>
        <!-- Below is another empty paragraph. -->
        <p class=MsoNormal><b></b></p>
        <p style=''></p>
        <p>
            <span lang=EN-US style='font-size:5.0pt;color:navy;mso-ansi-language:EN-`US'></span>
        </p>
    </body>
</html>

首次尝试:

$html = new DOMDocument("1.0", "UTF-8");
$html->loadHTMLFile("HTML File with Empty Paragraphs.html");
$pars = $html->getElementsByTagName("p");

/* removeChild foreach-loop */
foreach ($pars as $par) {
    if ($par->textContent == "") {
        $par->parentNode->removeChild($par);
    }
}

$html->saveHTMLFile("HTML File WithOut Empty Paragraphs.html");

成功

  • 删除没有style-attribute的空段落

但未能到:

  • 删除空段落 风格属性。

所以我在removeChild foreach-loop之前插入了removeStyleAttribute foreach-loop。 (我不介意删除非空段落的样式属性。)

第二次尝试:

$html = new DOMDocument("1.0", "UTF-8");
$html->loadHTMLFile("HTML File with Empty Paragraphs.html");
$pars = $html->getElementsByTagName("p");    

/* removeStyleAttribute foreach-loop */
foreach ($pars as $par) {
    if ($par->hasAttribute("style")) {
        $par->removeAttribute("style");
    }
}

/* removeChild foreach-loop */
foreach ($pars as $par) {
    if ($par->textContent == "") {
            $par->parentNode->removeChild($par);
    }
}

$html->saveHTMLFile("HTML File WithOut Empty Paragraphs.html");

成功

  • 从具有style属性的空段落中删除style-attributes。
  • 删除没有style-attributes的空段落。

但失败了!来:

  • 删除样式属性所在的空段落 除去。

所以我必须有两个removeChild foreach-loops,一个接一个。

第三次尝试:

$html = new DOMDocument("1.0", "UTF-8");
$html->loadHTMLFile("HTML File with Empty Paragraphs.html");
$pars = $html->getElementsByTagName("p");

/* removeStyleAttribute foreach-loop */
foreach ($pars as $par) {
    if ($par->hasAttribute("style")) {
        $par->removeAttribute("style");
    }
}

/* First removeChild foreach-loop */
foreach ($pars as $par) {
    if ($par->textContent == "") {
        $par->parentNode->removeChild($par);
    }
}

/* Second removeChild foreach-loop, identical to the first removeChild foreach-loop */
foreach ($pars as $par) {
    if ($par->textContent == "") {
        $par->parentNode->removeChild($par);
    }
}

$html->saveHTMLFile("HTML File WithOut Empty Paragraphs.html");

这完美无缺!,但有两个相同的循环,一个接着一个是奇怪的。

我也尝试过只使用一个循环。

第四次尝试:

$html = new DOMDocument("1.0", "UTF-8");
$html->loadHTMLFile("HTML File with Empty Paragraphs.html");
$pars = $html->getElementsByTagName("p");  

foreach ($pars as $par) {
    if ($par->textContent == "") {
        if ($par->hasAttribute("style")){
            $par->removeAttribute("style");
        }
        $par->parentNode->removeChild($par);
    }
}

$html->saveHTMLFile("HTML File WithOut Empty Paragraphs.html");

成功

  • 删除没有的空段落 样式属性,

但未能到:

  • 从包含它的空段落中删除style-attribute。
  • 使用style属性删除空段落。

2 个答案:

答案 0 :(得分:1)

getElementsByTagName返回的列表是动态的:从文档中删除节点也会从列表中删除它们。由于foreach不知道列表发生了变化,因此它很乐意转移到下一个项目 - 实际上是两个项目,因为DOMNodeList已重新排列。一些&lt; p&gt;标签只是简单地跳过了。

解决方案:使用for循环(使用$ pars-&gt; item(X)和$ pars-&gt; length)而不是foreach,但仅在节点删除时才递增。 (或者如果删除了一个,则总是递增和回溯。)

单独地:最后一个&lt; p&gt; (由于&lt; span&gt;周围的空格,因此未删除大的&lt; span&gt;)。使用trim()来摆脱它。

另请参阅http://forums.devnetwork.net/viewtopic.php?f=1&t=121114&p=623974中的回复。

答案 1 :(得分:0)

像Tomalak说的那样可能与空白有关。 尝试禁用“preserveWhiteSpace”:

$html->preserveWhiteSpace = false

嗯,我是新来的,如何将我的答案作为评论而非答案发送?