如何使用标签的ID删除标签及其所有内部HTML内容?

20

我有以下的HTML:

<html>
 <body>
 bla bla bla bla
  <div id="myDiv"> 
         more text
      <div id="anotherDiv">
           And even more text
      </div>
  </div>

  bla bla bla
 </body>
</html>

我想要删除从 <div id="anotherDiv"> 开始直到它的闭合 <div> 的所有内容。如何实现?


这个页面似乎存在编辑战。请澄清这个不明确的问题,以便研究人员受益。 - mickmackusa
删除单个特定元素和删除所有具有特定标签名称的标记之间存在很大的区别。 - mickmackusa
这个问题的每个正则表达式解决方案都是错误的,无论对于这个问题的任何解释,都会在许多不同的输入上以令人惊讶的方式失败。你需要一个DOM解析器,就像被接受的答案所使用的那样。无论你认为这个问题想要去掉一个<div>,还是通过它的ID去掉一个元素,都不能用正则表达式正确地完成任何一个选项。 - user229044
考虑使用正则表达式从<div data-attr="</div>"></div>中剥离<div>(按标签或按ID)。或者是从<div><script>foo("</div>")</script></div>等其他简单情况中剥离。这些情况都会破坏基于正则表达式的解决方案。 - user229044
7个回答

34
使用原生 DOM
$dom = new DOMDocument;
$dom->loadHTML($htmlString);
$xPath = new DOMXPath($dom);
$nodes = $xPath->query('//*[@id="anotherDiv"]');
if($nodes->item(0)) {
    $nodes->item(0)->parentNode->removeChild($nodes->item(0));
}
echo $dom->saveHTML();

如果我想在 DOM 中删除所有 div 标签,我需要修改什么? - Sisir
@Sisir 请查看 http://stackoverflow.com/questions/4177376/delete-all-elements-of-a-certain-type-from-an-xml-doc-using-php/4177407#4177407 - Gordon
1
是的,这个很有效。我一直想能够从HTML字符串中删除HTML标签,就像jQuery $(selector#id).remove()一样。这太棒了! - azzy81
@SubstanceD 如果你想要选择器,可以查看 phpQuery, Zend_Dom 或 QueryPath。个人而言,我更喜欢使用 XPath - Gordon

14

你可以使用preg_replace()函数,例如:

$string = preg_replace('/<div id="someid"[^>]+\>/i', "", $string);

1
这将删除所有的 div 而不仅仅是指定的一个。 - jigfox
你没有在任何地方指定它必须删除ID为myDiv的div吗? - rockstardev
1
这个答案绝对不能满足OP的需求。16 UVs意味着许多研究人员被误导,不理解问题和/或这个答案的作用。这个答案带来的负面影响远大于好处。总体信息应该是开发人员应该使用DOM解析器来操作有效的HTML。 - mickmackusa
1
问题是:我想删除从<div id="anotherDiv">开始直到其闭合<div>的所有内容。我该怎么做? 这个答案是不正确的。 - mickmackusa
这是不正确的,并且对于 <div id="someid" data-foo=">"> 会失败。你不能使用正则表达式来解决这个问题。 - user229044
显示剩余3条评论

5

使用本地XML操作库

假设您的HTML内容存储在变量$html中:

$html='<html>
 <body>
 bla bla bla bla
  <div id="myDiv"> 
         more text
      <div id="anotherDiv">
           And even more text
      </div>
  </div>

  bla bla bla
 </body>
</html>';

要按ID删除标签,请使用以下代码:

    $dom=new DOMDocument;

    $dom->validateOnParse = false;

    $dom->loadHTML( $html );

    // get the tag

    $div = $dom->getElementById('anotherDiv');

   // delete the tag

    if( $div && $div->nodeType==XML_ELEMENT_NODE ){

        $div->parentNode->removeChild( $div );
    }

    echo $dom->saveHTML();

请注意,某些版本的libxml需要存在doctype才能使用getElementById方法。在这种情况下,您可以在$html前面添加<!doctype>
$html = '<!doctype>' . $html;

另外,正如Gordon的回答所建议的那样,您可以使用DOMXPath通过xpath查找元素:

$dom=new DOMDocument;

$dom->validateOnParse = false;

$dom->loadHTML( $html );

$xp=new DOMXPath( $dom );

$col = $xp->query( '//div[ @id="anotherDiv" ]' );

if( !empty( $col ) ){

    foreach( $col as $node ){

        $node->parentNode->removeChild( $node );

    }

}

echo $dom->saveHTML();

第一种方法不受标签的限制。如果您想使用相同的id但不同的标签来使用第二种方法,比如说form,只需将//div[ @id="anotherDiv" ]中的//div替换为'//form'即可。

0

4
strip_tags() 方法不像他想的那样工作。虽然 strip_tags() 允许排除某些标签,但是如果您只想排除一个标签并包含所有其他标签,为什么要使用它呢? - Haim Evgi
从他的问题中,我无法真正确定他想要删除哪些标签。似乎他想要删除所有内容。感谢您的回答。 - ItsPronounced
啊,使用谷歌浏览器。他的内联标记没有显示出来。我刚在火狐浏览器中检查了一下,看到他的内联标记了。你是对的 :) 为什么谷歌浏览器没有显示出来? - ItsPronounced
strip_tags() 对我来说效果最好。原因是我的标签没有空格。这是迄今为止最简单的方法。谢谢。 - Alex Spencer
问题是:我想删除从<div id="anotherDiv">开始直到其闭合<div>的所有内容。我该怎么做? 这个答案是不正确的。 - mickmackusa

-1

这个怎么样?

// Strips only the given tags in the given HTML string.
function strip_tags_blacklist($html, $tags) {
    $html = preg_replace('/<'. $tags .'\b[^>]*>(.*?)<\/'. $tags .'>/is', "", $html);
    return $html;
}

1
正则表达式不考虑DOM,容易出现故障。使用合法的DOM解析技术将更加健壮、可靠和可扩展。没有理由声明$html(一个单一使用的变量);只需return preg_replace(...);。当标签属性值包含>时,此代码片段将失败。无需使用捕获组。 - mickmackusa
这个答案并不针对问题中使用 id 标签。这个答案是错误的,因为它会删除不应该被删除的元素。 - mickmackusa
这是不正确的,并且对于许多种输入都会失败,例如 strip_tags_blacklist('<script>let x = "<div>"></script><div>foo</div>', 'div') => <script>let x = "。您不能使用正则表达式来剥离或以其他方式与HTML交互。 - user229044

-1

我编写了以下代码来清除特定的标签和属性,由于使用了正则表达式,所以不能保证在所有情况下都能完全奏效,但对我而言这是一个公平的权衡:

// Strips only the given tags in the given HTML string.
function strip_tags_blacklist($html, $tags) {
    foreach ($tags as $tag) {
        $regex = '#<\s*' . $tag . '[^>]*>.*?<\s*/\s*'. $tag . '>#msi';
        $html = preg_replace($regex, '', $html);
    }
    return $html;
}

// Strips the given attributes found in the given HTML string.
function strip_attributes($html, $atts) {
    foreach ($atts as $att) {
        $regex = '#\b' . $att . '\b(\s*=\s*[\'"][^\'"]*[\'"])?(?=[^<]*>)#msi';
        $html = preg_replace($regex, '', $html);
    }
    return $html;
}

1
正则表达式不考虑DOM结构并且容易出错。使用合法的DOM解析技术将更加健壮、可靠和可扩展。迭代使用preg_调用会是低效的。模式修改器m是无用的。 - mickmackusa
1
此答案不针对在问题中使用 id 的标签。该答案是错误的,因为它会删除不应被删除的元素。 - mickmackusa

-1

在RafaSashi使用preg_replace()的答案之后,这里提供一个适用于单个标签或标签数组的版本:

/**
 * @param $str string
 * @param $tags string | array
 * @return string
 */

function strip_specific_tags ($str, $tags) {
  if (!is_array($tags)) { $tags = array($tags); }

  foreach ($tags as $tag) {
    $_str = preg_replace('/<\/' . $tag . '>/i', '', $str);
    if ($_str != $str) {
      $str = preg_replace('/<' . $tag . '[^>]*>/i', '', $_str);
    }
  }
  return $str;
}

1
问题是:我想删除从<div id="anotherDiv">开始直到其闭合<div>的所有内容。我该怎么做?这个答案是不正确的。 - mickmackusa
1
这个答案并不针对问题中使用 id 标签。这个答案是错误的,因为它会删除不应该被删除的元素。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接