使用PHP';s的DOM实现返回第一个';n';HTML字符串的字符


Using PHP's DOM implementation to return the first 'n' characters of an HTML string

给定一个HTML字符串,我想返回一个具有以下属性的修改后的字符串:

  1. 文本内容的前n个字符(HTML标记除外)应保留
  2. 满足n字符后的元素应完全删除
  3. 如果n字符不在元素的末尾,则同一元素中后面的文本不应保留
  4. n字符及其之前的元素上的标记应保留

基本上,我只想返回HTML的缩短版本,而不中断DOM结构,并且只基于文本内容的长度。

使用PHP的DOM实现,这似乎会过于复杂。使用模式匹配并不理想,因为修改后的字符串的条件可能会随着时间的推移而变化,而且每次都需要重写。

我是不是错过了一种更简单的方法?提前谢谢。

"使用PHP的DOM实现,这似乎过于复杂。"

真的吗

如果您想要<body>标记及其子节点中的前100个字符,这里有一个非常简单的DOM实现。您可以进一步调整以删除换行符和多余的空格/制表符,或者检查foreach$content字符串的长度,以中断循环并在达到一定数量的字符后停止串联。

$str = '...';
$dom = new DomDocument;
$dom->loadHTML($str);
$elements = $dom->getElementsByTagName('body');
$content = '';
foreach($elements as $node){
  foreach($node->childNodes as $child) {
    $content .= $child->nodeValue;
  }
}
echo substr($content, 0, 100);

更新

根据您的评论,这里有一个简单的方法来计算HTML节点内的字符数,并在达到指定的字符限制后删除所有标记。请注意,不能在原始foreach中执行删除操作,因为这会导致DOM对节点进行重新索引,并且不会得到预期的结果。相反,我们将要删除的节点存储在数组中,并在初始迭代后删除它们。

$str = '...';
$dom = new DomDocument;
$dom->preserveWhitespace = FALSE;
$dom->loadHTML($str);
$elements = $dom->getElementsByTagName('body');
$remove   = FALSE;
$maxChars = 100;
$content  = '';
$delete   = array();
foreach($elements as $node){
  foreach($node->childNodes as $child) {
    if ($remove) {
      $delete[] = $child;
    } else {
      $content .= $child->nodeValue;
      if ( ! $remove && strlen($content) >= $maxChars) {
        $remove = TRUE;
      }
    }
  }
}
foreach ($delete as $child) {
  $child->parentNode->removeChild($child);
}
$dom->formatOutput = TRUE;
echo $dom->saveHTML();