PHP DOM - удаление тегов span с оставлением их содержимого - PullRequest
2 голосов
/ 12 января 2011

Я хочу взять разметку как:

<span class="test">Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.</span>

и найдите в PHP лучший метод для удаления диапазона так, чтобы осталось следующее:

Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.

Я прочитал многие другие вопросы, касающиеся синтаксического анализа HTML с использованием PHP DOM вместо regex, но не смог найти способ обрезать промежутки с помощью PHP DOM, оставив содержимое HTML без изменений. Конечная цель состоит в том, чтобы иметь возможность вырезать из документа все теги span, оставляя их содержимое. Можно ли это сделать с помощью PHP DOM? Существует ли метод, обеспечивающий более высокую производительность и не основанный на анализе строк вместо анализа DOM?

Я использовал для этого регулярные выражения, без каких-либо проблем:

/<(\/)?(span)[^>]*>/i

Но я заинтересован в том, чтобы стать лучшим программистом PHP. И поскольку всегда есть возможность отключить регулярное выражение с плохо отформатированной разметкой, я ищу лучший путь. Я также рассмотрел использование strip_tags (), делая что-то вроде следующего:

public function strip_tags( $content, $tags_to_strip = array() )
{
    // All Valid XHTML tags
 $valid_tags = array(
  'a','abbr','acronym','address','area','b','base','bdo','big','blockquote','body','br','button','caption','cite',
  'code','col','colgroup','dd','del','dfn','div','dl','DOCTYPE','dt','em','fieldset','form','h1','h2','h3','h4',
  'h5','h6','head','html','hr','i','img','input','ins','kbd','label','legend','li','link','map','meta','noscript',
  'object','ol','optgroup','option','p','param','pre','q','samp','script','select','small','span','strong','style',
  'sub','sup','table','tbody','td','textarea','tfoot','th','thead','title','tr','tt','ul','var'
 );

    // Remove each tag to strip from the valid_tags array
 foreach ( $tags_to_strip as $tag ){
  $ndx = array_search( $tag, $valid_tags );
  if ( $ndx !== false ){
   unset( $valid_tags[ $ndx ] );
  }
 }

    // convert valid_tags array into param for strip_tags
 $valid_tags = implode( '><', $valid_tags );
 $valid_tags = "<$valid_tags>";

 $content = strip_tags( $content, $valid_tags );
 return $content;
}

Но это все еще разбор строки, а не разбор DOM. Так что, если текст имеет неправильную форму, возможно слишком много лишнего. Многие люди быстро предлагают использовать Simple HTML DOM Parser , но, глядя на исходный код, кажется, что он также использует регулярные выражения для анализа html.

Может ли это быть сделано с помощью DOM в PHP5, или есть лучший способ удалить теги, оставив их содержимое без изменений. Будет ли плохой практикой использовать Tidy или HTML Purifier для очистки текста, а затем использовать regex / HTML Simple HTML DOM parser на нем?

Библиотеки, подобные phpQuery , кажутся слишком тяжелыми для того, что кажется простым делом.

Ответы [ 2 ]

1 голос
/ 12 января 2011

Я использую следующую функцию для удаления узла без удаления его дочерних элементов:

function DOMRemove(DOMNode $from) {
    $sibling = $from->firstChild;
    do {
        $next = $sibling->nextSibling;
        $from->parentNode->insertBefore($sibling, $from);
    } while ($sibling = $next);
    $from->parentNode->removeChild($from);    
}

Например:

$dom = new DOMDocument;
$dom->load('myhtml.html');

$nodes = $dom->getElementsByTagName('span');
foreach ($nodes as $node) {
    DOMRemove($node);
}
echo $dom->saveHTML();

Даст вам:

Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.

Пока это:

$nodes = $dom->getElementsByTagName('a');
foreach ($nodes as $node) {
    DOMRemove($node);
}
echo $dom->saveHTML();

Даст вам:

<span class="test">Some text that is <strong>bolded</strong> and contains a link.</span>
0 голосов
/ 12 января 2011

Ну

По моему опыту, каждый раз, когда я работал с DOM, я немного терял в производительности по сравнению с простыми операциями stri.

С помощью вашей функции вы пытались строго фильтровать допустимые теги XHTML, но вам не нужен цикл с ручным сравнением, поскольку вы можете назначить всю эту задачу интерпретатору PHP через нативные функции.

Конечно, вы хорошо скомбинировали, чтобы добиться очень хорошей производительности (для меня 0,0002 миллисекунды), но вы можете попробовать объединить функции в одну строку, позволяя каждой функции выполнять свою собственную естественную работу.

Посмотрите, и вы поймете, о чем я говорю:

$text = '<span class="test">Some text that is <strong>bolded</strong> and contains a <a href="#">link</a>.</span>';

$validTags = array( 'a','abbr','acronym','address','area','b','base','bdo','big','blockquote','body','br','button','caption','cite',
  'code','col','colgroup','dd','del','dfn','div','dl','DOCTYPE','dt','em','fieldset','form','h1','h2','h3','h4',
  'h5','h6','head','html','hr','i','img','input','ins','kbd','label','legend','li','link','map','meta','noscript',
  'object','ol','optgroup','option','p','param','pre','q','samp','script','select','small','span','strong','style',
  'sub','sup','table','tbody','td','textarea','tfoot','th','thead','title','tr','tt','ul','var'
);

$tagsToStrip = array( 'span' );

var_dump( strip_tags( $text, sprintf( '<%s>', implode( '><', array_diff( $validTags, $tagsToStrip ) ) ) ) );

Я использовал ваш собственный список, но я объединил sprintf (), implode () и array_diff (), чтобы выполнить конкретные задачи для совместного достижения цели.

Надеюсь, это помогло.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...