【问题标题】:php remove html tags that surround no contentphp删除没有内容的html标签
【发布时间】:2014-09-12 16:01:49
【问题描述】:

我正在显示已在所见即所得编辑器中编写的内容(一个名为 $ps 的字符串,其中填充了 html)(未使用外部 css)并包含空格,例如

<p>

<span style="font-family: Calibri, sans-serif; font-size: 11pt;">
    <br></br>
</span>
<span style="font-size: 11pt; font-family: Calibri, sans-serif;">
</span>

</p>

我想使用 php 删除(因为我希望作者继续不小心添加空的东西)。

到目前为止,我的代码效率非常低:

$ps = preg_replace('#class="(.*?)"#', '',$ps);
$ps = preg_replace('#style="(.*?)"#', '',$ps);
$ps = preg_replace('#<br\s*/*>#i', '',$ps);
$ps = preg_replace('#<span\s*/*>#i', '',$ps);
$ps = preg_replace('#<p>\s*</p>#i', '',$ps);

这大约是一半好,留给我:

<p>

</p>
<p>

</p>

如果空的东西看起来有点不同,我怀疑它不会可靠地工作。

你能帮我建立一个更好的解决方案吗?我可以轻松实施?与我迄今为止的尝试不同,也许是一个有效的正则表达式..

谢谢!

【问题讨论】:

  • 第一件事(不管这是否是一个好方法) preg_replace 可以接受一组正则表达式。即:preg_replace(array('#class="(.*?)"#', '#style="(.*?)"#', '#&lt;br\s*/*&gt;#i', '#&lt;span\s*/*&gt;#i', '#&lt;p&gt;\s*&lt;/p&gt;#i'), '',$ps);
  • 我认为您应该使用DOMXPath 删除空节点。正则表达式不适用于 HTML。检查这 2 个 SO 解决方案。 stackoverflow.com/questions/8603237/…stackoverflow.com/questions/11744454/…
  • 用正则表达式解析 HTML 是一个悲伤的秘诀。当您的用户输入与您的期望不符时,您的正则表达式将会中断。例如,如果您的&lt;p&gt;&lt;/p&gt; 标签位于不同的行上怎么办?使用正则表达式修改 HTML 更糟糕。使用适当的 HTML 解析器。
  • 您可能会发现我对一个非常相似的问题的回答很有用:Remove all empty HTML tags?

标签: php html regex html-parsing


【解决方案1】:

我会使用 DOMDocument 而不是正则表达式:

$html = '<span style="font-family: Calibri, sans-serif; font-size: 11pt;">...';

$domd = new DOMDocument();
$domd->loadHTML($html);

$domx = new DOMXPath($domd);
$items = $domx->query("//*");

foreach($items as $item) {
  $item->removeAttribute("style");
  $item->removeAttribute("class");
}

echo $domd->saveHTML();

您还可以删除空节点,或者您需要删除的任何其他内容。

【讨论】:

  • if (trim($item-&gt;nodeValue) == '') $item-&gt;parentNode-&gt;removeChild($item); 之类的东西可能会这样做,虽然我还没有测试过
  • 到目前为止感谢大家!这个解决方案几乎完成了。我现在在 $html 和 if (trim($item->nodeValue) == '') $item->parentNode->removeChild($item);只删除第一个/一些出现的空节点。我还没弄清楚这取决于什么。
  • @user148585 您需要注意首先删除的内容,或者运行几次。如果跨度中有一个空跨度,那么内部跨度应该被删除,但外部跨度可能不会。
  • @wolffer-east 你能帮我解决复发问题吗?到目前为止,我已经残忍地完成了 $domd2->loadHTML($domd->saveHTML());并相应地复制了随后的内容,但没有成功。
【解决方案2】:

回应@ovi的回答中的评论,因为cmets中的代码块很丑

您可以运行它,直到它不再从元素集中删除任何内容。如果它是一个长文档,这会一直拖下去,但我想它会起作用。

例如

$changed = true;
while ($changed = true){
  $changed = false;
  foreach($items as $item) {
    if (trim($item->nodeValue) == ''){
      $item->parentNode->removeChild($item);
      $changed = true;
    }
  }
}

我重申,这可能需要相当长的时间。另外,我还没有测试过$item-&gt;parentNode-&gt;removeChild($item); 部分。

【讨论】:

  • 谢谢,我明白你的意思了。不幸的是,removeChild 以某种方式最终试图删除非对象?即使这个循环是查询后唯一要做的事情..
  • 不幸的是,我不是 domdocument 操作方面的专家。你可以试试(trim($item-&gt;nodeValue) == '' &amp;&amp; $child-&gt;nodeName != "#text")
  • 不幸的是,这并没有成功。非常感谢您的帮助!
猜你喜欢
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-03
  • 1970-01-01
  • 2021-10-09
  • 1970-01-01
  • 2018-10-28
相关资源
最近更新 更多